diff --git a/.github/workflows/ci-crypto-tests.yml b/.github/workflows/ci-crypto-tests.yml deleted file mode 100644 index 60bc264fa3..0000000000 --- a/.github/workflows/ci-crypto-tests.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Crypto Tests CI - -on: - # Triggers the workflow on any pull request and push to develop - push: - branches: [ develop ] - pull_request: - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - crypto-tests: - name: Crypto Tests with Synapse - runs-on: macos-11 - - concurrency: - # When running on develop, use the sha to allow all runs of this workflow to run concurrently. - # Otherwise only allow a single run of this workflow on each branch, automatically cancelling older runs. - group: ${{ github.ref == 'refs/heads/develop' && format('crypto-develop-{0}', github.sha) || format('crypto-{0}', github.ref) }} - cancel-in-progress: true - - steps: - - uses: actions/checkout@v2 - - # Cache for python env for Synapse - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Cache pip - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip - restore-keys: | - ${{ runner.os }}-pip- - ${{ runner.os }}- - # Cache for Xcode env - - uses: actions/cache@v2 - with: - path: Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - restore-keys: | - ${{ runner.os }}-pods- - - uses: actions/cache@v2 - with: - path: vendor/bundle - key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gems- - - name: Start synapse server - uses: michaelkaye/setup-matrix-synapse@v1.0.3 - with: - uploadLogs: true - httpPort: 8080 - disableRateLimiting: true - - - name: Bundle install - run: | - bundle config path vendor/bundle - bundle install --jobs 4 --retry 3 - # Main step - - name: Crypto tests - run: bundle exec fastlane test testplan:CryptoTests - - # Store artifacts - - uses: actions/upload-artifact@v2 - if: always() - with: - name: report.html - path: build/test/report.html - - uses: actions/upload-artifact@v2 - if: always() - with: - name: report.junit - path: build/test/report.junit - - uses: actions/upload-artifact@v2 - if: always() - with: - name: MatrixSDK-macOS.xcresult - path: build/test/MatrixSDK-macOS.xcresult/ - - # Upload coverage - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 diff --git a/.github/workflows/ci-integration-tests.yml b/.github/workflows/ci-integration-tests.yml index 694840f7f3..81fd1e95a4 100644 --- a/.github/workflows/ci-integration-tests.yml +++ b/.github/workflows/ci-integration-tests.yml @@ -12,7 +12,7 @@ on: jobs: integration-tests: name: Integration Tests - runs-on: macos-11 + runs-on: macos-13 concurrency: # When running on develop, use the sha to allow all runs of this workflow to run concurrently. diff --git a/.github/workflows/ci-lint.yml b/.github/workflows/ci-lint.yml index 4b346189dc..458fd030e6 100644 --- a/.github/workflows/ci-lint.yml +++ b/.github/workflows/ci-lint.yml @@ -12,7 +12,7 @@ on: jobs: lint: name: pod lib lint - runs-on: macos-11 + runs-on: macos-13 concurrency: # When running on develop, use the sha to allow all runs of this workflow to run concurrently. diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml index ad5395fea7..90a46ffb3d 100644 --- a/.github/workflows/ci-unit-tests.yml +++ b/.github/workflows/ci-unit-tests.yml @@ -12,7 +12,7 @@ on: jobs: unit-tests: name: Unit Tests - runs-on: macos-11 + runs-on: macos-13 concurrency: # When running on develop, use the sha to allow all runs of this workflow to run concurrently. diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3455e2bbc5..59ab296d94 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,7 +10,7 @@ jobs: unit-tests: name: Unit Tests with sanitizer checks - runs-on: macos-11 + runs-on: macos-13 steps: - uses: actions/checkout@v2 diff --git a/CHANGES.md b/CHANGES.md index 8412d19900..404ac4b973 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,107 @@ +## Changes in 0.27.6 (2024-02-07) + +No significant changes. + + +## Changes in 0.27.5 (2024-01-09) + +🐛 Bugfixes + +- Update regex for email address to be aligned email format in RFC 5322 ([#1826](https://github.com/matrix-org/matrix-ios-sdk/pull/1826)) + +🧱 Build + +- Update CocoaPods and other gems. ([#1835](https://github.com/matrix-org/matrix-ios-sdk/pull/1835)) + + +## Changes in 0.27.4 (2023-11-28) + +🐛 Bugfixes + +- Fix unhandled callback when the session is nil. ([#1833](https://github.com/matrix-org/matrix-ios-sdk/pull/1833)) + + +## Changes in 0.27.3 (2023-10-04) + +🐛 Bugfixes + +- Prevent crash when sending file with unrecognised file extension (no associated mime type) (mimetype) + +🧱 Build + +- Update Cocoapods to 1.13.0. ([#1820](https://github.com/matrix-org/matrix-ios-sdk/pull/1820)) + + +## Changes in 0.27.2 (2023-09-12) + +🐛 Bugfixes + +- Fix | QR code verification failing due to incorrect encoding padding ([#1816](https://github.com/vector-im/element-ios/issues/1816)) + + +## Changes in 0.27.1 (2023-08-29) + +✨ Features + +- Delegate OIDC compatibility flag added. ([#1811](https://github.com/matrix-org/matrix-ios-sdk/pull/1811)) +- Added the authentication property to the well known. ([#1812](https://github.com/matrix-org/matrix-ios-sdk/pull/1812)) +- Function that allows to generate from the well known authentication, a logout mas URL given the device ID. ([#1813](https://github.com/matrix-org/matrix-ios-sdk/pull/1813)) + +🐛 Bugfixes + +- Fixes power level events force unwrap crash ([#1809](https://github.com/matrix-org/matrix-ios-sdk/pull/1809)) +- Prevent keyed archiver encoding crashes when writing read receipts to the file store ([#1810](https://github.com/vector-im/element-ios/issues/1810)) +- Fix incoming push notifications not triggering sounds ([#7636](https://github.com/vector-im/element-ios/issues/7636)) + + +## Changes in 0.27.0 (2023-08-15) + +✨ Features + +- Add support for device hydration through the Crypto SDK (uses MSC3814) ([#1807](https://github.com/matrix-org/matrix-ios-sdk/pull/1807)) + +🐛 Bugfixes + +- Fix parsing logic for legacy location events ([#1801](https://github.com/matrix-org/matrix-ios-sdk/pull/1801)) + +⚠️ API Changes + +- Remove MXDehydrationService and old client methods. ([#1807](https://github.com/matrix-org/matrix-ios-sdk/pull/1807)) + + +## Changes in 0.26.12 (2023-06-21) + +🐛 Bugfixes + +- Ignore push rules with unknown condition kinds ([#7601](https://github.com/vector-im/element-ios/issues/7601)) + + +## Changes in 0.26.11 (2023-06-13) + +🙌 Improvements + +- MSC3912 implementation: the stable property with_relations has been renamed with_rel_types ([#7563](https://github.com/vector-im/element-ios/issues/7563)) +- Updated Jitsi meet sdk to 8.1.2-lite. ([#7565](https://github.com/vector-im/element-ios/issues/7565)) +- MSC3987 implementation: the 'dont_notify' action for a push_rule is now deprecated and replaced by an empty action list. ([#7576](https://github.com/vector-im/element-ios/issues/7576)) + +🐛 Bugfixes + +- Fixes a bug where an unhelpful message is shown rather than the threads empty state. ([#7551](https://github.com/vector-im/element-ios/issues/7551)) + + +## Changes in 0.26.10 (2023-05-16) + +🙌 Improvements + +- Crypto: Enable Crypto SDK by default ([#1770](https://github.com/matrix-org/matrix-ios-sdk/pull/1770)) +- Crypto: Deprecate MXLegacyCrypto ([#1772](https://github.com/matrix-org/matrix-ios-sdk/pull/1772)) + +🐛 Bugfixes + +- Poll: Refreshing the poll when receiving pollEnd can break the chronological order in the store. ([#1776](https://github.com/matrix-org/matrix-ios-sdk/pull/1776)) +- Fix breadcrumb list not updating when leaving a room. Contributed by @JanNikGra. ([#1777](https://github.com/vector-im/element-ios/issues/1777)) + + ## Changes in 0.26.9 (2023-04-18) 🐛 Bugfixes diff --git a/Gemfile b/Gemfile index 294361724c..2aa841dabd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" gem "fastlane" -gem "cocoapods", '~>1.11.2' +gem "cocoapods", '~>1.14.3' gem "xcode-install" gem "slather" diff --git a/Gemfile.lock b/Gemfile.lock index c0c6a10288..317baa44e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,49 +1,55 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) + CFPropertyList (3.0.6) rexml - activesupport (6.1.7) + activesupport (7.1.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.1) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.674.0) - aws-sdk-core (3.168.4) + aws-eventstream (1.3.0) + aws-partitions (1.859.0) + aws-sdk-core (3.188.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.61.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (1.73.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.117.2) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-s3 (1.140.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.7.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) + base64 (0.2.0) + bigdecimal (3.1.4) claide (1.1.0) clamp (1.3.2) - cocoapods (1.11.3) + cocoapods (1.14.3) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.11.3) + cocoapods-core (= 1.14.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) @@ -51,10 +57,10 @@ GEM gh_inspector (~> 1.0) molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (>= 1.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.11.3) - activesupport (>= 5.0, < 7) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.14.3) + activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) @@ -64,7 +70,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -76,19 +82,21 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.2) + connection_pool (2.4.1) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20231109) dotenv (2.8.1) + drb (2.2.0) + ruby2_keywords emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.94.0) - faraday (1.10.2) + excon (0.104.0) + faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -116,8 +124,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.6) - fastlane (2.211.0) + fastimage (2.2.7) + fastlane (2.217.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -138,10 +146,11 @@ GEM google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) @@ -149,20 +158,20 @@ GEM security (= 0.1.3) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - ffi (1.15.5) + ffi (1.16.3) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.31.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-core (0.9.1) + google-apis-androidpublisher_v3 (0.53.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -171,30 +180,29 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.16.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-playcustomapp_v1 (0.12.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.0) - google-cloud-storage (1.44.0) + google-cloud-errors (1.3.1) + google-cloud-storage (1.45.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.29.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.3.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -202,80 +210,77 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.12.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) jmespath (1.6.2) json (2.6.3) - jwt (2.5.0) - memoist (0.16.2) + jwt (2.7.1) mini_magick (4.12.0) - mini_mime (1.1.2) - mini_portile2 (2.8.0) - minitest (5.16.3) + mini_mime (1.1.5) + mini_portile2 (2.8.5) + minitest (5.20.0) molinillo (0.8.0) multi_json (1.15.0) - multipart-post (2.0.0) + multipart-post (2.3.0) + mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) naturally (2.2.1) netrc (0.11.0) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) + nokogiri (1.15.5) + mini_portile2 (~> 2.8.2) racc (~> 1.4) optparse (0.1.1) os (1.1.4) - plist (3.6.0) + plist (3.7.0) public_suffix (4.0.7) - racc (1.6.1) - rake (13.0.6) + racc (1.7.3) + rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally - slather (2.7.3) + slather (2.8.0) CFPropertyList (>= 2.2, < 4) activesupport clamp (~> 1.3) - nokogiri (>= 1.13.9) + nokogiri (>= 1.14.3) xcodeproj (~> 1.21) terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) - webrick (1.7.0) + unicode-display_width (2.5.0) + webrick (1.8.1) word_wrap (1.0.0) xcode-install (2.8.1) claide (>= 0.9.1) fastlane (>= 2.1.0, < 3.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -286,13 +291,12 @@ GEM rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - zeitwerk (2.6.6) PLATFORMS ruby DEPENDENCIES - cocoapods (~> 1.11.2) + cocoapods (~> 1.14.3) fastlane slather xcode-install diff --git a/MatrixSDK.podspec b/MatrixSDK.podspec index 6022d8c602..3da81b2aa0 100644 --- a/MatrixSDK.podspec +++ b/MatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MatrixSDK" - s.version = "0.26.9" + s.version = "0.27.6" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC @@ -43,7 +43,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 'MatrixSDKCrypto', '0.3.4', :configurations => ["DEBUG", "RELEASE"], :inhibit_warnings => true + ss.dependency 'MatrixSDKCrypto', '0.3.13', :configurations => ["DEBUG", "RELEASE"], :inhibit_warnings => true end s.subspec 'JingleCallStack' do |ss| @@ -60,7 +60,7 @@ Pod::Spec.new do |s| # Use WebRTC framework included in Jitsi Meet SDK # Use the lite version so we don't add a dependency on Giphy. - ss.ios.dependency 'JitsiMeetSDKLite', '7.0.1-lite' + ss.ios.dependency 'JitsiMeetSDKLite', '8.1.2-lite' end end diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 5b37d76164..d3f648edfb 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 02CAD439217DD12F0074700B /* MXContentScanResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 02CAD434217DD12F0074700B /* MXContentScanResult.m */; }; 02CAD43A217DD12F0074700B /* MXContentScanEncryptedBody.m in Sources */ = {isa = PBXBuildFile; fileRef = 02CAD436217DD12F0074700B /* MXContentScanEncryptedBody.m */; }; 02CAD43B217DD12F0074700B /* MXContentScanEncryptedBody.h in Headers */ = {isa = PBXBuildFile; fileRef = 02CAD437217DD12F0074700B /* MXContentScanEncryptedBody.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0B1445B384D92B384C697D27 /* libPods-MatrixSDKTests-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F334B2A67FCBF95C014AA3F8 /* libPods-MatrixSDKTests-iOS.a */; }; + 0C90662A1D71E1FAC81AE9B9 /* libPods-MatrixSDK-MatrixSDK-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14EB974DFB592986747766BB /* libPods-MatrixSDK-MatrixSDK-macOS.a */; }; 180F858427A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 180F858227A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 180F858527A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 180F858227A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 180F858627A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 180F858327A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.m */; }; @@ -44,6 +44,8 @@ 1838928927031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 1838928527031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18937E7C273A5AE500902626 /* MXPollRelationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 18937E79273A5AB000902626 /* MXPollRelationTests.m */; }; 18937E7D273A5AE500902626 /* MXPollRelationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 18937E79273A5AB000902626 /* MXPollRelationTests.m */; }; + 189B8D102A864C250088D7CE /* DehydrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189B8D0F2A864C250088D7CE /* DehydrationService.swift */; }; + 189B8D112A864C250088D7CE /* DehydrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189B8D0F2A864C250088D7CE /* DehydrationService.swift */; }; 18C26C3D273C031900805154 /* PollAggregator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C26C3C273C031900805154 /* PollAggregator.swift */; }; 18C26C3E273C032900805154 /* PollAggregator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C26C3C273C031900805154 /* PollAggregator.swift */; }; 18C26C4A273C0B3A00805154 /* PollAggregator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C26C3C273C031900805154 /* PollAggregator.swift */; }; @@ -664,8 +666,6 @@ 3A59A52C25A7B1B000DDA1FC /* MXOutboundSessionInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A59A52825A7B1B000DDA1FC /* MXOutboundSessionInfo.m */; }; 3A7509BB26FC61DF00B85773 /* MXSpaceNotificationCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7509BA26FC61DF00B85773 /* MXSpaceNotificationCounter.swift */; }; 3A7509BC26FC61DF00B85773 /* MXSpaceNotificationCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7509BA26FC61DF00B85773 /* MXSpaceNotificationCounter.swift */; }; - 3A7B8D0E267FCF7200D9DD96 /* MXDehydrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A7B8CFD267FCD9B00D9DD96 /* MXDehydrationTests.m */; }; - 3A7B8D13267FCF7300D9DD96 /* MXDehydrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A7B8CFD267FCD9B00D9DD96 /* MXDehydrationTests.m */; }; 3A858DDA2750EE3F006322C1 /* MXHomeserverCapabilitiesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A858DD92750EE3F006322C1 /* MXHomeserverCapabilitiesService.swift */; }; 3A858DDD275121DB006322C1 /* MXHomeserverCapabilitiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A858DDB275120D1006322C1 /* MXHomeserverCapabilitiesTests.swift */; }; 3A858DDE275121DC006322C1 /* MXHomeserverCapabilitiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A858DDB275120D1006322C1 /* MXHomeserverCapabilitiesTests.swift */; }; @@ -682,10 +682,6 @@ 3AB5EBB5270B332B0058703A /* MXSpaceStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB5EBB3270B332B0058703A /* MXSpaceStore.swift */; }; 3AB5EBB7270ED1C00058703A /* MXSpaceFileStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB5EBB6270ED1C00058703A /* MXSpaceFileStore.swift */; }; 3AB5EBB8270ED1C00058703A /* MXSpaceFileStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB5EBB6270ED1C00058703A /* MXSpaceFileStore.swift */; }; - 3AC135D92640335100EE1E74 /* MXDehydrationService.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AC135D72640335100EE1E74 /* MXDehydrationService.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3AC135DA2640335100EE1E74 /* MXDehydrationService.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AC135D72640335100EE1E74 /* MXDehydrationService.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3AC135DB2640335100EE1E74 /* MXDehydrationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AC135D82640335100EE1E74 /* MXDehydrationService.m */; }; - 3AC135DC2640335100EE1E74 /* MXDehydrationService.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AC135D82640335100EE1E74 /* MXDehydrationService.m */; }; 3AC13802264482A100EE1E74 /* MXExportedOlmDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AC13800264482A100EE1E74 /* MXExportedOlmDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3AC13803264482A100EE1E74 /* MXExportedOlmDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AC13800264482A100EE1E74 /* MXExportedOlmDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3AC13804264482A100EE1E74 /* MXExportedOlmDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AC13801264482A100EE1E74 /* MXExportedOlmDevice.m */; }; @@ -694,6 +690,7 @@ 3AD4F232274B922D003F47FE /* MXRoomAliasAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4F230274B922C003F47FE /* MXRoomAliasAvailabilityChecker.swift */; }; 3AF85F9226FC7AE800A9E67B /* MXSpaceNotificationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */; }; 3AF85F9326FC7AE800A9E67B /* MXSpaceNotificationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */; }; + 45A464600F0E7F90846883CC /* libPods-MatrixSDKTests-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 57A13C13901D6F9F486DA5EA /* libPods-MatrixSDKTests-iOS.a */; }; 66398BA527A4085B00466E89 /* MXRefreshResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 66398BA427A4085B00466E89 /* MXRefreshResponse.m */; }; 66398BA627A4085B00466E89 /* MXRefreshResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 66398BA427A4085B00466E89 /* MXRefreshResponse.m */; }; 66836AB727CFA17200515780 /* MXEventStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66836AB527CFA17200515780 /* MXEventStreamService.swift */; }; @@ -706,7 +703,6 @@ 66AC9D26278CE627002E9B8F /* MXRefreshTokenData.m in Sources */ = {isa = PBXBuildFile; fileRef = 66AC9D22278CE626002E9B8F /* MXRefreshTokenData.m */; }; 71DE22E01BC7C51200284153 /* MXReceiptData.m in Sources */ = {isa = PBXBuildFile; fileRef = 71DE22DC1BC7C51200284153 /* MXReceiptData.m */; }; 71DE22E11BC7C51200284153 /* MXReceiptData.h in Headers */ = {isa = PBXBuildFile; fileRef = 71DE22DD1BC7C51200284153 /* MXReceiptData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 851DDA07C82BD4CC7FD759B9 /* libPods-MatrixSDK-MatrixSDK-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B986396B45069E35651CB05 /* libPods-MatrixSDK-MatrixSDK-macOS.a */; }; 8EC511042568216B00EC4E5B /* MXTaggedEventInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC511022568216B00EC4E5B /* MXTaggedEventInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8EC511052568216B00EC4E5B /* MXTaggedEventInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC511022568216B00EC4E5B /* MXTaggedEventInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8EC511062568216B00EC4E5B /* MXTaggedEventInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC511032568216B00EC4E5B /* MXTaggedEventInfo.m */; }; @@ -726,6 +722,11 @@ 92634B831EF2E3C400DB9F60 /* MXCallKitConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 92634B811EF2E3C400DB9F60 /* MXCallKitConfiguration.m */; }; 9274AFE81EE580240009BEB6 /* MXCallKitAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9274AFE61EE580240009BEB6 /* MXCallKitAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9274AFE91EE580240009BEB6 /* MXCallKitAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9274AFE71EE580240009BEB6 /* MXCallKitAdapter.m */; }; + 9F40FADC16DC5965A1DF9CBE /* libPods-MatrixSDK-MatrixSDK-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D431D5CB06B98B8AEB4784FB /* libPods-MatrixSDK-MatrixSDK-iOS.a */; }; + A75CAD692A9796DE00F06072 /* MXWellKnownAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = A75CAD682A9796DE00F06072 /* MXWellKnownAuthentication.m */; }; + A75CAD6A2A9796DE00F06072 /* MXWellKnownAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = A75CAD682A9796DE00F06072 /* MXWellKnownAuthentication.m */; }; + A75CAD6C2A979AC500F06072 /* MXWellKnownAuthentication.h in Headers */ = {isa = PBXBuildFile; fileRef = A75CAD6B2A97970500F06072 /* MXWellKnownAuthentication.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A75CAD6D2A979AC600F06072 /* MXWellKnownAuthentication.h in Headers */ = {isa = PBXBuildFile; fileRef = A75CAD6B2A97970500F06072 /* MXWellKnownAuthentication.h */; settings = {ATTRIBUTES = (Public, ); }; }; A780624E27B2CE74005780C0 /* FileManager+Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = A780624C27B2CE74005780C0 /* FileManager+Backup.swift */; }; A780624F27B2CE74005780C0 /* FileManager+Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = A780624C27B2CE74005780C0 /* FileManager+Backup.swift */; }; A780625027B2CE74005780C0 /* FileManager+AppGroupContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A780624D27B2CE74005780C0 /* FileManager+AppGroupContainer.swift */; }; @@ -1354,7 +1355,7 @@ C6F935891E5B3BE600FC34BF /* MXEventTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F935841E5B3BE600FC34BF /* MXEventTimeline.swift */; }; C6F9358A1E5B3BE600FC34BF /* MXEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F935861E5B3BE600FC34BF /* MXEvent.swift */; }; C6F9358B1E5B3BE600FC34BF /* MXJSONModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F935871E5B3BE600FC34BF /* MXJSONModels.swift */; }; - D2461BACB7E83C3F1286DBC1 /* libPods-MatrixSDKTests-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 213706C00A0F9A05CBD5D352 /* libPods-MatrixSDKTests-macOS.a */; }; + E3576F1500ED9D36EC9D319F /* libPods-MatrixSDKTests-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D2A414A8F1B7AE81BE479B8 /* libPods-MatrixSDKTests-macOS.a */; }; EC05473425FF8A3C0047ECD7 /* MXVirtualRoomInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC05473225FF8A3C0047ECD7 /* MXVirtualRoomInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC05473525FF8A3C0047ECD7 /* MXVirtualRoomInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC05473225FF8A3C0047ECD7 /* MXVirtualRoomInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC05473625FF8A3C0047ECD7 /* MXVirtualRoomInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EC05473325FF8A3C0047ECD7 /* MXVirtualRoomInfo.m */; }; @@ -2013,7 +2014,6 @@ F082946E1DB66C3D00CEAB63 /* MXInvite3PID.m in Sources */ = {isa = PBXBuildFile; fileRef = F082946C1DB66C3D00CEAB63 /* MXInvite3PID.m */; }; F08B8D5C1E014711006171A8 /* NSData+MatrixSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = F08B8D5A1E014711006171A8 /* NSData+MatrixSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; F08B8D5D1E014711006171A8 /* NSData+MatrixSDK.m in Sources */ = {isa = PBXBuildFile; fileRef = F08B8D5B1E014711006171A8 /* NSData+MatrixSDK.m */; }; - F0A41D81FB8F6D0A318D50AC /* libPods-MatrixSDK-MatrixSDK-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C18C158CE4559BEB13794DB /* libPods-MatrixSDK-MatrixSDK-iOS.a */; }; F0C34CBB1C18C93700C36F09 /* MXSDKOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = F0C34CBA1C18C93700C36F09 /* MXSDKOptions.m */; }; /* End PBXBuildFile section */ @@ -2065,6 +2065,7 @@ 02CAD436217DD12F0074700B /* MXContentScanEncryptedBody.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXContentScanEncryptedBody.m; sourceTree = ""; }; 02CAD437217DD12F0074700B /* MXContentScanEncryptedBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXContentScanEncryptedBody.h; sourceTree = ""; }; 07A279C2DC9BE095AB590A6E /* Pods-MatrixSDK-MatrixSDK-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDK-MatrixSDK-macOS.debug.xcconfig"; path = "Target Support Files/Pods-MatrixSDK-MatrixSDK-macOS/Pods-MatrixSDK-MatrixSDK-macOS.debug.xcconfig"; sourceTree = ""; }; + 14EB974DFB592986747766BB /* libPods-MatrixSDK-MatrixSDK-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDK-MatrixSDK-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 180F858227A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXWellKnownTileServerConfig.h; sourceTree = ""; }; 180F858327A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXWellKnownTileServerConfig.m; sourceTree = ""; }; 18121F73273E6CED00B68ADF /* MXPollBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXPollBuilderTests.swift; sourceTree = ""; }; @@ -2077,12 +2078,13 @@ 1838928427031D1D003F0C4F /* MXRoomNameStringLocalizerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomNameStringLocalizerProtocol.h; sourceTree = ""; }; 1838928527031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXSendReplyEventStringLocalizerProtocol.h; sourceTree = ""; }; 18937E79273A5AB000902626 /* MXPollRelationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXPollRelationTests.m; sourceTree = ""; }; + 189B8D0F2A864C250088D7CE /* DehydrationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DehydrationService.swift; sourceTree = ""; }; 18C26C3C273C031900805154 /* PollAggregator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollAggregator.swift; sourceTree = ""; }; 18C26C4C273C0E9A00805154 /* MXPollAggregatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXPollAggregatorTests.swift; sourceTree = ""; }; 18C26C51273C16C700805154 /* MXEventContentPollStart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXEventContentPollStart.h; sourceTree = ""; }; 18C26C52273C16C700805154 /* MXEventContentPollStart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXEventContentPollStart.m; sourceTree = ""; }; 1D18B4F281A93ADB785B4800 /* Pods-MatrixSDKTests-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDKTests-iOS.release.xcconfig"; path = "Target Support Files/Pods-MatrixSDKTests-iOS/Pods-MatrixSDKTests-iOS.release.xcconfig"; sourceTree = ""; }; - 213706C00A0F9A05CBD5D352 /* libPods-MatrixSDKTests-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDKTests-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2D2A414A8F1B7AE81BE479B8 /* libPods-MatrixSDKTests-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDKTests-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D8EE909E54EE5334E1FD271 /* Pods-MatrixSDKTests-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDKTests-macOS.release.xcconfig"; path = "Target Support Files/Pods-MatrixSDKTests-macOS/Pods-MatrixSDKTests-macOS.release.xcconfig"; sourceTree = ""; }; 3209682F26396385005D64ED /* AllTestsWithSanitizers.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AllTestsWithSanitizers.xctestplan; sourceTree = ""; }; 3209683026396385005D64ED /* UnitTestsWithSanitizers.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = UnitTestsWithSanitizers.xctestplan; sourceTree = ""; }; @@ -2574,7 +2576,6 @@ 3A59A52725A7B1B000DDA1FC /* MXOutboundSessionInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXOutboundSessionInfo.h; sourceTree = ""; }; 3A59A52825A7B1B000DDA1FC /* MXOutboundSessionInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXOutboundSessionInfo.m; sourceTree = ""; }; 3A7509BA26FC61DF00B85773 /* MXSpaceNotificationCounter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSpaceNotificationCounter.swift; sourceTree = ""; }; - 3A7B8CFD267FCD9B00D9DD96 /* MXDehydrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXDehydrationTests.m; sourceTree = ""; }; 3A858DD92750EE3F006322C1 /* MXHomeserverCapabilitiesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXHomeserverCapabilitiesService.swift; sourceTree = ""; }; 3A858DDB275120D1006322C1 /* MXHomeserverCapabilitiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXHomeserverCapabilitiesTests.swift; sourceTree = ""; }; 3A858DE027517C0E006322C1 /* MXRoomCapabilityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXRoomCapabilityType.swift; sourceTree = ""; }; @@ -2583,14 +2584,12 @@ 3A9E2B4228EB3960000DB2A7 /* MXMatrixVersionsUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXMatrixVersionsUnitTests.swift; sourceTree = ""; }; 3AB5EBB3270B332B0058703A /* MXSpaceStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSpaceStore.swift; sourceTree = ""; }; 3AB5EBB6270ED1C00058703A /* MXSpaceFileStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSpaceFileStore.swift; sourceTree = ""; }; - 3AC135D72640335100EE1E74 /* MXDehydrationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXDehydrationService.h; sourceTree = ""; }; - 3AC135D82640335100EE1E74 /* MXDehydrationService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXDehydrationService.m; sourceTree = ""; }; 3AC13800264482A100EE1E74 /* MXExportedOlmDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXExportedOlmDevice.h; sourceTree = ""; }; 3AC13801264482A100EE1E74 /* MXExportedOlmDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXExportedOlmDevice.m; sourceTree = ""; }; 3AD4F230274B922C003F47FE /* MXRoomAliasAvailabilityChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXRoomAliasAvailabilityChecker.swift; sourceTree = ""; }; 3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSpaceNotificationState.swift; sourceTree = ""; }; 415A2B7BEAF8D5462A575DAF /* Pods-MatrixSDK-MatrixSDK-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDK-MatrixSDK-iOS.release.xcconfig"; path = "Target Support Files/Pods-MatrixSDK-MatrixSDK-iOS/Pods-MatrixSDK-MatrixSDK-iOS.release.xcconfig"; sourceTree = ""; }; - 4C18C158CE4559BEB13794DB /* libPods-MatrixSDK-MatrixSDK-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDK-MatrixSDK-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 57A13C13901D6F9F486DA5EA /* libPods-MatrixSDKTests-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDKTests-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 66398BA427A4085B00466E89 /* MXRefreshResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXRefreshResponse.m; sourceTree = ""; }; 66398BA727A408C000466E89 /* MXRefreshResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXRefreshResponse.h; sourceTree = ""; }; 66836AB527CFA17200515780 /* MXEventStreamService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXEventStreamService.swift; sourceTree = ""; }; @@ -2600,7 +2599,6 @@ 71DE22DC1BC7C51200284153 /* MXReceiptData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXReceiptData.m; sourceTree = ""; }; 71DE22DD1BC7C51200284153 /* MXReceiptData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXReceiptData.h; sourceTree = ""; }; 74B6BABAFA35199D61B18B6F /* Pods-MatrixSDKTests-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDKTests-iOS.debug.xcconfig"; path = "Target Support Files/Pods-MatrixSDKTests-iOS/Pods-MatrixSDKTests-iOS.debug.xcconfig"; sourceTree = ""; }; - 7B986396B45069E35651CB05 /* libPods-MatrixSDK-MatrixSDK-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDK-MatrixSDK-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 8EC511022568216B00EC4E5B /* MXTaggedEventInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXTaggedEventInfo.h; sourceTree = ""; }; 8EC511032568216B00EC4E5B /* MXTaggedEventInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXTaggedEventInfo.m; sourceTree = ""; }; 8EC51108256822B400EC4E5B /* MXTaggedEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXTaggedEvents.h; sourceTree = ""; }; @@ -2614,6 +2612,8 @@ 9274AFE61EE580240009BEB6 /* MXCallKitAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCallKitAdapter.h; sourceTree = ""; }; 9274AFE71EE580240009BEB6 /* MXCallKitAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCallKitAdapter.m; sourceTree = ""; }; A0B1217E295306F700E704C2 /* MXAggregatedPollsUpdaterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXAggregatedPollsUpdaterTests.swift; sourceTree = ""; }; + A75CAD682A9796DE00F06072 /* MXWellKnownAuthentication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXWellKnownAuthentication.m; sourceTree = ""; }; + A75CAD6B2A97970500F06072 /* MXWellKnownAuthentication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXWellKnownAuthentication.h; sourceTree = ""; }; A780624C27B2CE74005780C0 /* FileManager+Backup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FileManager+Backup.swift"; sourceTree = ""; }; A780624D27B2CE74005780C0 /* FileManager+AppGroupContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FileManager+AppGroupContainer.swift"; sourceTree = ""; }; A816247B25F60C7700A46F05 /* MXDeviceListOperationsPoolUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXDeviceListOperationsPoolUnitTests.swift; sourceTree = ""; }; @@ -2753,6 +2753,7 @@ C6F935841E5B3BE600FC34BF /* MXEventTimeline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXEventTimeline.swift; sourceTree = ""; }; C6F935861E5B3BE600FC34BF /* MXEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXEvent.swift; sourceTree = ""; }; C6F935871E5B3BE600FC34BF /* MXJSONModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXJSONModels.swift; sourceTree = ""; }; + D431D5CB06B98B8AEB4784FB /* libPods-MatrixSDK-MatrixSDK-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDK-MatrixSDK-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; D6E6641895924FF16C6E5767 /* Pods-MatrixSDK-MatrixSDK-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDK-MatrixSDK-iOS.debug.xcconfig"; path = "Target Support Files/Pods-MatrixSDK-MatrixSDK-iOS/Pods-MatrixSDK-MatrixSDK-iOS.debug.xcconfig"; sourceTree = ""; }; E4E572A32459F0F8110BBFAC /* Pods-MatrixSDKTests-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDKTests-macOS.debug.xcconfig"; path = "Target Support Files/Pods-MatrixSDKTests-macOS/Pods-MatrixSDKTests-macOS.debug.xcconfig"; sourceTree = ""; }; E5463BF2B60AC232D46943D5 /* Pods-MatrixSDK-MatrixSDK-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDK-MatrixSDK-macOS.release.xcconfig"; path = "Target Support Files/Pods-MatrixSDK-MatrixSDK-macOS/Pods-MatrixSDK-MatrixSDK-macOS.release.xcconfig"; sourceTree = ""; }; @@ -3056,6 +3057,7 @@ ED8F1D3A2885BB2D00F897E7 /* MXCryptoProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoProtocols.swift; sourceTree = ""; }; ED997855292E2877006B5248 /* MXSessionStartupProgressUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSessionStartupProgressUnitTests.swift; sourceTree = ""; }; EDA2CDD528F5C4230088ACE7 /* MXQRCodeTransactionV2UnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXQRCodeTransactionV2UnitTests.swift; sourceTree = ""; }; + EDA40A0429E9D6BE00C0CAB9 /* MXKeyProviderStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyProviderStub.swift; sourceTree = ""; }; EDA40A0829E9E2BF00C0CAB9 /* legacy_version2_account.realm */ = {isa = PBXFileReference; lastKnownFileType = file; path = legacy_version2_account.realm; sourceTree = ""; }; EDA40A0929E9E2BF00C0CAB9 /* legacy_verified_account.realm */ = {isa = PBXFileReference; lastKnownFileType = file; path = legacy_verified_account.realm; sourceTree = ""; }; EDA40A0A29E9E2BF00C0CAB9 /* legacy_unverified_account.realm */ = {isa = PBXFileReference; lastKnownFileType = file; path = legacy_unverified_account.realm; sourceTree = ""; }; @@ -3112,7 +3114,6 @@ F08B8D5B1E014711006171A8 /* NSData+MatrixSDK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+MatrixSDK.m"; sourceTree = ""; }; F0C34CB91C18C80000C36F09 /* MXSDKOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXSDKOptions.h; sourceTree = ""; }; F0C34CBA1C18C93700C36F09 /* MXSDKOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXSDKOptions.m; sourceTree = ""; }; - F334B2A67FCBF95C014AA3F8 /* libPods-MatrixSDKTests-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixSDKTests-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -3120,7 +3121,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - F0A41D81FB8F6D0A318D50AC /* libPods-MatrixSDK-MatrixSDK-iOS.a in Frameworks */, + 9F40FADC16DC5965A1DF9CBE /* libPods-MatrixSDK-MatrixSDK-iOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3129,7 +3130,7 @@ buildActionMask = 2147483647; files = ( 3226DC3819DEED3B00866530 /* MatrixSDK.framework in Frameworks */, - 0B1445B384D92B384C697D27 /* libPods-MatrixSDKTests-iOS.a in Frameworks */, + 45A464600F0E7F90846883CC /* libPods-MatrixSDKTests-iOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3137,7 +3138,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 851DDA07C82BD4CC7FD759B9 /* libPods-MatrixSDK-MatrixSDK-macOS.a in Frameworks */, + 0C90662A1D71E1FAC81AE9B9 /* libPods-MatrixSDK-MatrixSDK-macOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3146,7 +3147,7 @@ buildActionMask = 2147483647; files = ( B1E09A132397FA950057C069 /* MatrixSDK.framework in Frameworks */, - D2461BACB7E83C3F1286DBC1 /* libPods-MatrixSDKTests-macOS.a in Frameworks */, + E3576F1500ED9D36EC9D319F /* libPods-MatrixSDKTests-macOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3193,10 +3194,10 @@ 0A3A436ED42FC8689721A09E /* Frameworks */ = { isa = PBXGroup; children = ( - 4C18C158CE4559BEB13794DB /* libPods-MatrixSDK-MatrixSDK-iOS.a */, - 7B986396B45069E35651CB05 /* libPods-MatrixSDK-MatrixSDK-macOS.a */, - F334B2A67FCBF95C014AA3F8 /* libPods-MatrixSDKTests-iOS.a */, - 213706C00A0F9A05CBD5D352 /* libPods-MatrixSDKTests-macOS.a */, + D431D5CB06B98B8AEB4784FB /* libPods-MatrixSDK-MatrixSDK-iOS.a */, + 14EB974DFB592986747766BB /* libPods-MatrixSDK-MatrixSDK-macOS.a */, + 57A13C13901D6F9F486DA5EA /* libPods-MatrixSDKTests-iOS.a */, + 2D2A414A8F1B7AE81BE479B8 /* libPods-MatrixSDKTests-macOS.a */, ); name = Frameworks; sourceTree = ""; @@ -3482,6 +3483,8 @@ 32CF439C2371AF9500907C56 /* MXWellknownIntegrations.m */, 180F858227A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h */, 180F858327A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.m */, + A75CAD682A9796DE00F06072 /* MXWellKnownAuthentication.m */, + A75CAD6B2A97970500F06072 /* MXWellKnownAuthentication.h */, ); path = AutoDiscovery; sourceTree = ""; @@ -4237,7 +4240,6 @@ 324DD2BA246C3ADE00377005 /* MXCryptoSecretStorageTests.m */, 322D01C322492B0700150C68 /* MXCryptoShareTests.m */, 322A51D71D9E846800C8536D /* MXCryptoTests.m */, - 3A7B8CFD267FCD9B00D9DD96 /* MXDehydrationTests.m */, 3281E89D19E299C000976E1A /* MXErrorUnitTests.m */, B146D4FC21A5C0BC00D8C2C6 /* MXEventScanStoreUnitTests.m */, 32A31BC020D3F4C4005916C7 /* MXFilterTests.m */, @@ -4500,8 +4502,7 @@ 3AC1379326432ED500EE1E74 /* Dehydration */ = { isa = PBXGroup; children = ( - 3AC135D72640335100EE1E74 /* MXDehydrationService.h */, - 3AC135D82640335100EE1E74 /* MXDehydrationService.m */, + 189B8D0F2A864C250088D7CE /* DehydrationService.swift */, ); path = Dehydration; sourceTree = ""; @@ -5293,6 +5294,7 @@ ED8F1D312885AC5700F897E7 /* Device+Stub.swift */, ED1FE90A2912E13A0046F722 /* DecryptedEvent+Stub.swift */, EDC8C40A2968A9F7003792C5 /* MXKeysQuerySchedulerUnitTests.swift */, + EDA40A0429E9D6BE00C0CAB9 /* MXKeyProviderStub.swift */, ); path = CryptoMachine; sourceTree = ""; @@ -5820,7 +5822,6 @@ ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */, EC60EDC6265CFEA800B39A4E /* MXRoomSyncUnreadNotifications.h in Headers */, 329FB1791A0A74B100A5E88E /* MXTools.h in Headers */, - 3AC135D92640335100EE1E74 /* MXDehydrationService.h in Headers */, 322691321E5EF77D00966A6E /* MXDeviceListOperation.h in Headers */, EC60EE06265CFFF400B39A4E /* MXGroupSyncProfile.h in Headers */, 32481A841C03572900782AD3 /* MXRoomAccountData.h in Headers */, @@ -5931,6 +5932,7 @@ 3287164F23C4C11F00D720CA /* MXKeyVerificationManager_Private.h in Headers */, 32F634AB1FC5E3480054EF49 /* MXEventDecryptionResult.h in Headers */, 32999DE322DCD1AD004FF987 /* MXPusherData.h in Headers */, + A75CAD6C2A979AC500F06072 /* MXWellKnownAuthentication.h in Headers */, 3284A5A01DB7C00600A09972 /* MXCryptoStore.h in Headers */, 32442FB121EDD21300D2411B /* MXKeyBackupPassword.h in Headers */, 3259CD531DF860C300186944 /* MXRealmCryptoStore.h in Headers */, @@ -6292,6 +6294,7 @@ EC8A53DD25B1BCC6004E0802 /* MXThirdPartyProtocol.h in Headers */, ECF29BDF264195320053E6D6 /* MXAssertedIdentityModel.h in Headers */, B14EF31A2397E90400758AF0 /* MXScanRealmProvider.h in Headers */, + A75CAD6D2A979AC600F06072 /* MXWellKnownAuthentication.h in Headers */, 32549AFA23F2E2790002576B /* MXKeyVerificationReady.h in Headers */, B14EF31B2397E90400758AF0 /* MXEventUnsignedData.h in Headers */, B14EF31C2397E90400758AF0 /* MXEventEditsListener.h in Headers */, @@ -6312,7 +6315,6 @@ B19A309F240424BD00FB6F35 /* MXQRCodeTransaction_Private.h in Headers */, 3AC13803264482A100EE1E74 /* MXExportedOlmDevice.h in Headers */, B14EF3262397E90400758AF0 /* MXEventScanStoreDelegate.h in Headers */, - 3AC135DA2640335100EE1E74 /* MXDehydrationService.h in Headers */, B14EF3292397E90400758AF0 /* MXAutoDiscovery.h in Headers */, EC8A53D725B1BCC6004E0802 /* MXThirdPartyUserInstance.h in Headers */, EC60EDD1265CFECC00B39A4E /* MXRoomSyncSummary.h in Headers */, @@ -6511,12 +6513,10 @@ TargetAttributes = { 32C6F92C19DD814400EA4E9C = { CreatedOnToolsVersion = 6.0; - DevelopmentTeam = 86J6LQ96WM; LastSwiftMigration = 1020; }; 32C6F93719DD814400EA4E9C = { CreatedOnToolsVersion = 6.0; - DevelopmentTeam = 86J6LQ96WM; LastSwiftMigration = 1020; }; B1E09A0D2397FA950057C069 = { @@ -6703,6 +6703,7 @@ 32A1513F1DAF768D00400192 /* MXOlmInboundGroupSession.m in Sources */, 3259CFE626026A6F00C365DB /* MXRestClient+Extensions.swift in Sources */, EC60ED91265CFD3B00B39A4E /* MXRoomSync.m in Sources */, + 189B8D102A864C250088D7CE /* DehydrationService.swift in Sources */, 3AB5EBB4270B332B0058703A /* MXSpaceStore.swift in Sources */, EC8A53A125B1BC77004E0802 /* MXCallSelectAnswerEventContent.m in Sources */, B14EECE72577F76100448735 /* MXLoginSSOFlow.m in Sources */, @@ -6753,7 +6754,6 @@ EC60ED87265CFD0700B39A4E /* MXRoomsSyncResponse.m in Sources */, 3213301E228B190F0070BA9B /* MXRealmAggregationsMapper.m in Sources */, 8EC511062568216B00EC4E5B /* MXTaggedEventInfo.m in Sources */, - 3AC135DB2640335100EE1E74 /* MXDehydrationService.m in Sources */, 32792BDD2296B90A00F4FC9D /* MXAggregatedEditsUpdater.m in Sources */, ECDBE69028E5D961000C83AF /* MXClientInformationService.swift in Sources */, ED44F01428180EAB00452A5D /* MXSharedHistoryKeyManager.swift in Sources */, @@ -6950,6 +6950,7 @@ A780625027B2CE74005780C0 /* FileManager+AppGroupContainer.swift in Sources */, 9274AFE91EE580240009BEB6 /* MXCallKitAdapter.m in Sources */, 3274538C23FD918800438328 /* MXKeyVerificationByToDeviceRequest.m in Sources */, + A75CAD692A9796DE00F06072 /* MXWellKnownAuthentication.m in Sources */, ED6DAC1828C799E300ECDCB6 /* MXRoomKeyResult.swift in Sources */, ECB6FA952683811800A941E4 /* MXiOSAudioOutputRouter.swift in Sources */, EC131B0A2758D56600712964 /* MXThreadNotificationsCount.swift in Sources */, @@ -7257,7 +7258,6 @@ ECAE7AEC24ED75F1002FA813 /* MXHTTPAdditionalHeadersUnitTests.m in Sources */, 32AF9292241112850008A0FD /* MXCryptoSecretShareTests.m in Sources */, ED8F1D342885ADE200F897E7 /* MXCryptoProtocolStubs.swift in Sources */, - 3A7B8D0E267FCF7200D9DD96 /* MXDehydrationTests.m in Sources */, 3281E8A019E2CC1200976E1A /* MXHTTPClientTests.m in Sources */, 321809B919EEBF3000377451 /* MXEventTests.m in Sources */, B1B44319283D00CA00BB26F4 /* MXMegolmDecryptionUnitTests.swift in Sources */, @@ -7341,6 +7341,7 @@ B19EC8A3260E134A00543BEC /* MXRoomInitialStateEventBuilder.swift in Sources */, B14EF1CA2397E90400758AF0 /* MXOlmInboundGroupSession.m in Sources */, B14EF1CB2397E90400758AF0 /* MXRoomAccountData.m in Sources */, + 189B8D112A864C250088D7CE /* DehydrationService.swift in Sources */, 3AB5EBB5270B332B0058703A /* MXSpaceStore.swift in Sources */, B14EF1CC2397E90400758AF0 /* MXEventAnnotationChunk.m in Sources */, B14EF1CD2397E90400758AF0 /* MXRealmEventScanStore.m in Sources */, @@ -7589,6 +7590,7 @@ A780625127B2CE74005780C0 /* FileManager+AppGroupContainer.swift in Sources */, B14EF23B2397E90400758AF0 /* MXKeyBackupData.m in Sources */, B14EF23C2397E90400758AF0 /* MXJSONModels.m in Sources */, + A75CAD6A2A9796DE00F06072 /* MXWellKnownAuthentication.m in Sources */, EC8A538E25B1BC77004E0802 /* MXCallSessionDescription.m in Sources */, ED6DAC1928C799E300ECDCB6 /* MXRoomKeyResult.swift in Sources */, EC131B0B2758D56600712964 /* MXThreadNotificationsCount.swift in Sources */, @@ -7739,7 +7741,6 @@ B14EF27B2397E90400758AF0 /* MXOlmSessionResult.m in Sources */, EC5C560D2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.m in Sources */, ECDA763627B527BA000C48CF /* MXEvent+Extensions.swift in Sources */, - 3AC135DC2640335100EE1E74 /* MXDehydrationService.m in Sources */, B14EF27C2397E90400758AF0 /* MXRestClient.swift in Sources */, 32AF929A24115D8B0008A0FD /* MXPendingSecretShareRequest.m in Sources */, B14EF27D2397E90400758AF0 /* MXKeyBackup.m in Sources */, @@ -7893,7 +7894,6 @@ B1E09A292397FD080057C069 /* MXLoggerUnitTests.m in Sources */, B1E09A492398028D0057C069 /* MXSelfSignedHomeserverTests.m in Sources */, 32B0E3E523A384D40054FF1A /* MXAggregatedReferenceTests.m in Sources */, - 3A7B8D13267FCF7300D9DD96 /* MXDehydrationTests.m in Sources */, ED7019E32886C29400FC31B9 /* Device+Stub.swift in Sources */, 32D5D16423E400A600E3E37C /* MXRoomSummaryTrustTests.m in Sources */, B1E09A1B2397FCE90057C069 /* MXAggregatedReactionTests.m in Sources */, @@ -8111,11 +8111,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = D6E6641895924FF16C6E5767 /* Pods-MatrixSDK-MatrixSDK-iOS.debug.xcconfig */; buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 86J6LQ96WM; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -8140,11 +8138,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 415A2B7BEAF8D5462A575DAF /* Pods-MatrixSDK-MatrixSDK-iOS.release.xcconfig */; buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 86J6LQ96WM; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -8170,7 +8166,6 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; - DEVELOPMENT_TEAM = 86J6LQ96WM; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -8199,7 +8194,6 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; - DEVELOPMENT_TEAM = 86J6LQ96WM; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -8222,7 +8216,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 07A279C2DC9BE095AB590A6E /* Pods-MatrixSDK-MatrixSDK-macOS.debug.xcconfig */; buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; @@ -8252,7 +8245,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = E5463BF2B60AC232D46943D5 /* Pods-MatrixSDK-MatrixSDK-macOS.release.xcconfig */; buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; diff --git a/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-macOS.xcscheme b/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-macOS.xcscheme index e475cbcaa6..978c9f172e 100644 --- a/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-macOS.xcscheme +++ b/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-macOS.xcscheme @@ -64,9 +64,6 @@ - - diff --git a/MatrixSDK/Background/Crypto/MXBackgroundCryptoV2.swift b/MatrixSDK/Background/Crypto/MXBackgroundCryptoV2.swift index d2db3ede3f..a785fb0168 100644 --- a/MatrixSDK/Background/Crypto/MXBackgroundCryptoV2.swift +++ b/MatrixSDK/Background/Crypto/MXBackgroundCryptoV2.swift @@ -53,7 +53,8 @@ class MXBackgroundCryptoV2: MXBackgroundCrypto { toDevice: syncResponse.toDevice, deviceLists: syncResponse.deviceLists, deviceOneTimeKeysCounts: syncResponse.deviceOneTimeKeysCount ?? [:], - unusedFallbackKeys: syncResponse.unusedFallbackKeys + unusedFallbackKeys: syncResponse.unusedFallbackKeys, + nextBatchToken: syncResponse.nextBatch ) } catch { log.error("Failed handling sync response", context: error) diff --git a/MatrixSDK/Background/MXBackgroundPushRulesManager.swift b/MatrixSDK/Background/MXBackgroundPushRulesManager.swift index 34d386ad22..8c3d3bffc0 100644 --- a/MatrixSDK/Background/MXBackgroundPushRulesManager.swift +++ b/MatrixSDK/Background/MXBackgroundPushRulesManager.swift @@ -42,7 +42,9 @@ import Foundation } } - flatRules = tmpRules + // vector-im/element-ios/issues/7636 + // Intentionally disable new backend push rules as they're not handle properly and break notification sounds + flatRules = tmpRules.filter { $0.ruleId != ".m.rule.is_user_mention" && $0.ruleId != ".m.rule.is_room_mention" } } } private var flatRules: [MXPushRule] = [] @@ -82,6 +84,12 @@ import Foundation return false } + // Support for MSC3987: The dont_notify push rule action is deprecated. + if rule.actions.isEmpty { + return rule.enabled + } + + // Compatibility support. for ruleAction in rule.actions { guard let action = ruleAction as? MXPushRuleAction else { continue } if action.actionType == MXPushRuleActionTypeDontNotify { @@ -123,7 +131,9 @@ import Foundation var conditionsOk: Bool = true var runEquivalent: Bool = false - guard let kind = MXPushRuleKind(identifier: rule.kind) else { continue } + guard let kind = MXPushRuleKind(identifier: rule.kind) else { + continue + } switch kind { case .override, .underride: diff --git a/MatrixSDK/Background/MXBackgroundSyncService.swift b/MatrixSDK/Background/MXBackgroundSyncService.swift index 5fe4e5abfb..efb2ad4d1f 100644 --- a/MatrixSDK/Background/MXBackgroundSyncService.swift +++ b/MatrixSDK/Background/MXBackgroundSyncService.swift @@ -67,7 +67,6 @@ public enum MXBackgroundSyncServiceError: Error { /// - Parameter credentials: account credentials public init( withCredentials credentials: MXCredentials, - isCryptoSDKEnabled: Bool = false, persistTokenDataHandler: MXRestClientPersistTokenDataHandler? = nil, unauthenticatedHandler: MXRestClientUnauthenticatedHandler? = nil ) { @@ -90,16 +89,9 @@ public enum MXBackgroundSyncServiceError: Error { 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 - if isCryptoSDKEnabled { - MXLog.debug("[MXBackgroundSyncService] init: constructing crypto v2") - crypto = MXBackgroundCryptoV2(credentials: credentials, restClient: restClient) - } else { - MXLog.debug("[MXBackgroundSyncService] init: constructing legacy crypto") - crypto = MXLegacyBackgroundCrypto(credentials: credentials, resetBackgroundCryptoStore: resetBackgroundCryptoStore) - } + MXLog.debug("[MXBackgroundSyncService] init: constructing crypto") + crypto = MXBackgroundCryptoV2(credentials: credentials, restClient: restClient) pushRulesManager = MXBackgroundPushRulesManager(withCredentials: credentials) MXLog.debug("[MXBackgroundSyncService] init complete") diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift index f444ca2eb2..fe8df357e7 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift @@ -31,7 +31,7 @@ import MatrixSDKCrypto internal init(identity: UserIdentity, isVerified: Bool) { switch identity { - case .own(let userId, _, let masterKey, let selfSigningKey, let userSigningKey): + case .own(let userId, _, let masterKey, let userSigningKey, let selfSigningKey): self.userId = userId // Note: `trustsOurOwnDevice` is not currently used, instead using second `isVerified` parameter self.masterKeys = .init(jsonString: masterKey) diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift index d46a648376..7abf8b4c9d 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift @@ -126,7 +126,7 @@ class MXCrossSigningV2: NSObject, MXCrossSigning { // If we are considered verified, there is no need for a verification upgrade // after migrating from legacy crypto if myUserCrossSigningKeys?.trustLevel.isVerified == true { - MXSDKOptions.sharedInstance().cryptoSDKFeature?.needsVerificationUpgrade = false + MXSDKOptions.sharedInstance().cryptoMigrationDelegate?.needsVerificationUpgrade = false } log.debug("Cross signing state refreshed, new state: \(state)") diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index b92cd55f8a..370cf71aff 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -187,7 +187,8 @@ extension MXCryptoMachine: MXCryptoSyncing { toDevice: MXToDeviceSyncResponse?, deviceLists: MXDeviceListResponse?, deviceOneTimeKeysCounts: [String: NSNumber], - unusedFallbackKeys: [String]? + unusedFallbackKeys: [String]?, + nextBatchToken: String ) throws -> MXToDeviceSyncResponse { let events = toDevice?.jsonString() ?? "[]" let deviceChanges = DeviceLists( @@ -200,20 +201,30 @@ extension MXCryptoMachine: MXCryptoSyncing { events: events, deviceChanges: deviceChanges, keyCounts: keyCounts, - unusedFallbackKeys: unusedFallbackKeys + unusedFallbackKeys: unusedFallbackKeys, + nextBatchToken: nextBatchToken ) - guard - let json = MXTools.deserialiseJSONString(result) as? [Any], - let toDevice = MXToDeviceSyncResponse(fromJSON: ["events": json]) - else { + var deserialisedToDeviceEvents = [Any]() + for toDeviceEvent in result.toDeviceEvents { + guard let deserialisedToDeviceEvent = MXTools.deserialiseJSONString(toDeviceEvent) else { + log.failure("Failed deserialising to device event", context: [ + "result": result + ]) + return MXToDeviceSyncResponse() + } + + deserialisedToDeviceEvents.append(deserialisedToDeviceEvent) + } + + guard let toDeviceSyncResponse = MXToDeviceSyncResponse(fromJSON: ["events": deserialisedToDeviceEvents]) else { log.failure("Result cannot be serialized", context: [ "result": result ]) return MXToDeviceSyncResponse() } - return toDevice + return toDeviceSyncResponse } func downloadKeysIfNecessary(users: [String]) async throws { @@ -308,7 +319,7 @@ extension MXCryptoMachine: MXCryptoSyncing { } private func markRequestAsSent(requestId: String, requestType: RequestType, response: String? = nil) throws { - try self.machine.markRequestAsSent(requestId: requestId, requestType: requestType, response: response ?? "") + try self.machine.markRequestAsSent(requestId: requestId, requestType: requestType, responseBody: response ?? "") } private func handleOutgoingRequests() async throws { @@ -358,6 +369,10 @@ extension MXCryptoMachine: MXCryptoDevicesSource { return nil } } + + func dehydratedDevices() -> DehydratedDevicesProtocol { + machine.dehydratedDevices() + } } extension MXCryptoMachine: MXCryptoUserIdentitySource { @@ -583,7 +598,12 @@ extension MXCryptoMachine: MXCryptoCrossSigning { } func exportCrossSigningKeys() -> CrossSigningKeyExport? { - machine.exportCrossSigningKeys() + do { + return try machine.exportCrossSigningKeys() + } catch { + log.error("Failed exporting cross signing keys", context: error) + return nil + } } func importCrossSigningKeys(export: CrossSigningKeyExport) { @@ -593,6 +613,23 @@ extension MXCryptoMachine: MXCryptoCrossSigning { log.error("Failed importing cross signing keys", context: error) } } + + func queryMissingSecretsFromOtherSessions() async throws { + let isMissingSecrets = try machine.queryMissingSecretsFromOtherSessions() + + if (isMissingSecrets) { + // Out-of-sync check if there are any secret request to send out as a result of + // the missing secret request + for request in try machine.outgoingRequests() { + if case .toDevice(_, let eventType, _) = request { + if (eventType == kMXEventTypeStringSecretRequest) { + try await handleRequest(request) + } + } + } + } + } + } extension MXCryptoMachine: MXCryptoVerifying { @@ -784,7 +821,7 @@ extension MXCryptoMachine: MXCryptoBackup { } do { - let verification = try machine.verifyBackup(authData: string) + let verification = try machine.verifyBackup(backupInfo: string) return verification.trusted } catch { log.error("Failed verifying backup", context: error) diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift index 65dee0f900..b9b4dabc75 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -35,7 +35,8 @@ protocol MXCryptoSyncing: MXCryptoIdentity { toDevice: MXToDeviceSyncResponse?, deviceLists: MXDeviceListResponse?, deviceOneTimeKeysCounts: [String: NSNumber], - unusedFallbackKeys: [String]? + unusedFallbackKeys: [String]?, + nextBatchToken: String ) throws -> MXToDeviceSyncResponse func processOutgoingRequests() async throws @@ -50,6 +51,7 @@ protocol MXCryptoSyncing: MXCryptoIdentity { protocol MXCryptoDevicesSource: MXCryptoIdentity { func device(userId: String, deviceId: String) -> Device? func devices(userId: String) -> [Device] + func dehydratedDevices() -> DehydratedDevicesProtocol } /// Source of user identities and their cryptographic trust status @@ -88,6 +90,8 @@ protocol MXCryptoCrossSigning: MXCryptoUserIdentitySource, MXCryptoDevicesSource func bootstrapCrossSigning(authParams: [AnyHashable: Any]) async throws func exportCrossSigningKeys() -> CrossSigningKeyExport? func importCrossSigningKeys(export: CrossSigningKeyExport) + + func queryMissingSecretsFromOtherSessions() async throws } /// Verification functionality diff --git a/MatrixSDK/Crypto/Dehydration/DehydrationService.swift b/MatrixSDK/Crypto/Dehydration/DehydrationService.swift new file mode 100644 index 0000000000..6f4ccb9c77 --- /dev/null +++ b/MatrixSDK/Crypto/Dehydration/DehydrationService.swift @@ -0,0 +1,219 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import MatrixSDKCrypto + +enum DehydrationServiceError: Error { + case failedDehydration(Error) + case noDehydratedDeviceAvailable(Error) + case failedRehydration(Error) + case invalidRehydratedDeviceData + case failedStoringSecret(Error) + case failedRetrievingSecret(Error) + case failedRetrievingPrivateKey(Error) + case invalidSecretStorageDefaultKeyId + case failedRetrievingToDeviceEvents(Error) + case failedDeletingDehydratedDevice(Error) +} + +@objcMembers +public class DehydrationService: NSObject { + let deviceDisplayName = "Backup Device" + let restClient: MXRestClient + let secretStorage: MXSecretStorage + let dehydratedDevices: DehydratedDevicesProtocol + + + init(restClient: MXRestClient, secretStorage: MXSecretStorage, dehydratedDevices: DehydratedDevicesProtocol) { + self.restClient = restClient + self.secretStorage = secretStorage + self.dehydratedDevices = dehydratedDevices + } + + public func runDeviceDehydrationFlow(privateKeyData: Data) async { + do { + try await _runDeviceDehydrationFlow(privateKeyData: privateKeyData) + } catch { + MXLog.error("Failed device dehydration flow", context: error) + } + } + + private func _runDeviceDehydrationFlow(privateKeyData: Data) async throws { + guard let secretStorageKeyId = self.secretStorage.defaultKeyId() else { + throw DehydrationServiceError.invalidSecretStorageDefaultKeyId + } + + let secretId = MXSecretId.dehydratedDevice.takeUnretainedValue() as String + + // If we have a dehydration pickle key stored on the backend, use it to rehydrate a device, then process + // that device's events and then create a new dehydrated device + if secretStorage.hasSecret(withSecretId: secretId, withSecretStorageKeyId: secretStorageKeyId) { + // If available, retrieve the base64 encoded pickle key from the backend + let base64PickleKey = try await retrieveSecret(forSecretId: secretId, secretStorageKey: secretStorageKeyId, privateKeyData: privateKeyData) + + // Convert it back to Data + let pickleKeyData = MXBase64Tools.data(fromBase64: base64PickleKey) + + let rehydrationResult = await rehydrateDevice(pickleKeyData: [UInt8](pickleKeyData)) + switch rehydrationResult { + case .success((let deviceId, let rehydratedDevice)): + // Fetch and process the to device events available on the dehydrated device + try await processToDeviceEvents(rehydratedDevice: rehydratedDevice, deviceId: deviceId) + + // And attempt to delete the dehydrated device but ignore failures + try? await deleteDehydratedDevice(deviceId: deviceId) + case .failure(let error): + // If no dehydrated devices are available just continue and create a new one + if case .noDehydratedDeviceAvailable = error { + break + } else { + throw error + } + } + + // Finally, create a new dehydrated device with the same pickle key + try await dehydrateDevice(pickleKeyData: [UInt8](pickleKeyData)) + } else { // Otherwise, generate a new dehydration pickle key, store it and dehydrate a device + // Generate a new dehydration pickle key + var pickleKeyData = [UInt8](repeating: 0, count: 32) + _ = SecRandomCopyBytes(kSecRandomDefault, 32, &pickleKeyData) + + // Convert it to unpadded base 64 + let base64PickleKey = MXBase64Tools.unpaddedBase64(from: Data(bytes: pickleKeyData, count: 32)) + + // Store it on the backend + try await storeSecret(base64PickleKey, secretId: secretId, secretStorageKeys: [secretStorageKeyId: privateKeyData]) + + // Dehydrate a new device using the new pickle key + try await dehydrateDevice(pickleKeyData: pickleKeyData) + } + } + + // MARK: - Secret storage + + private func storeSecret(_ unpaddedBase64Secret: String, secretId: String, secretStorageKeys: [String: Data]) async throws { + try await withCheckedThrowingContinuation { continuation in + self.secretStorage.storeSecret(unpaddedBase64Secret, withSecretId: secretId, withSecretStorageKeys: secretStorageKeys) { secretId in + MXLog.info("Stored secret with secret id: \(secretId)") + continuation.resume() + } failure: { error in + MXLog.error("Failed storing secret", context: error) + continuation.resume(throwing: DehydrationServiceError.failedStoringSecret(error)) + } + } + } + + private func retrieveSecret(forSecretId secretId: String, secretStorageKey: String, privateKeyData: Data) async throws -> String { + try await withCheckedThrowingContinuation { continuation in + self.secretStorage.secret(withSecretId: secretId, withSecretStorageKeyId: secretStorageKey, privateKey: privateKeyData) { secret in + MXLog.info("Retrieved secret with secret id: \(secretId)") + continuation.resume(returning: secret) + } failure: { error in + MXLog.error("Failed retrieving secret", context: error) + continuation.resume(throwing: DehydrationServiceError.failedRetrievingSecret(error)) + } + } + } + + // MARK: - Device dehydration + + private func dehydrateDevice(pickleKeyData: [UInt8]) async throws { + let dehydratedDevice = dehydratedDevices.create() + + let requestDetails = try dehydratedDevice.keysForUpload(deviceDisplayName: deviceDisplayName, pickleKey: [UInt8](pickleKeyData)) + + let parameters = MXDehydratedDeviceCreationParameters() + parameters.body = requestDetails.body + + return try await withCheckedThrowingContinuation { continuation in + restClient.createDehydratedDevice(parameters) { deviceId in + MXLog.info("Successfully created dehydrated device with id: \(deviceId)") + continuation.resume() + } failure: { error in + MXLog.error("Failed creating dehydrated device", context: error) + continuation.resume(throwing: DehydrationServiceError.failedDehydration(error)) + } + } + } + + private func rehydrateDevice(pickleKeyData: [UInt8]) async -> Result<(deviceId: String, rehydratedDevice: RehydratedDeviceProtocol), DehydrationServiceError> { + await withCheckedContinuation { continuation in + self.restClient.retrieveDehydratedDevice { [weak self] dehydratedDevice in + guard let self else { return } + + MXLog.info("Successfully retrieved dehydrated device with id: \(dehydratedDevice.deviceId)") + + guard let deviceDataJSON = MXTools.serialiseJSONObject(dehydratedDevice.deviceData) else { + continuation.resume(returning: .failure(DehydrationServiceError.invalidRehydratedDeviceData)) + return + } + + do { + let rehydratedDevice = try self.dehydratedDevices.rehydrate(pickleKey: [UInt8](pickleKeyData), deviceId: dehydratedDevice.deviceId, deviceData: deviceDataJSON) + continuation.resume(returning: .success((dehydratedDevice.deviceId, rehydratedDevice))) + } catch { + continuation.resume(returning: .failure(DehydrationServiceError.failedRehydration(error))) + } + } failure: { error in + MXLog.error("Failed retrieving dehidrated device", context: error) + if let mxError = MXError(nsError: error), + mxError.errcode == kMXErrCodeStringNotFound { + continuation.resume(returning: .failure(DehydrationServiceError.noDehydratedDeviceAvailable(error))) + } else { + continuation.resume(returning: .failure(DehydrationServiceError.failedRehydration(error))) + } + } + } + } + + private func deleteDehydratedDevice(deviceId: String) async throws { + try await withCheckedThrowingContinuation { continuation in + restClient.deleteDehydratedDevice { + MXLog.info("Deleted dehydrated device with id: \(deviceId)") + continuation.resume() + } failure: { error in + MXLog.error("Failed retrieving dehydrated device events", context: error) + continuation.resume(throwing: DehydrationServiceError.failedRetrievingPrivateKey(error)) + } + } + } + + // MARK: - To device event processing + + private func processToDeviceEvents(rehydratedDevice: RehydratedDeviceProtocol, deviceId: String) async throws { + var dehydratedDeviceEventsResponse: MXDehydratedDeviceEventsResponse? + + repeat { + let response = try await retrieveToDeviceEvents(deviceId: deviceId, nextBatch: dehydratedDeviceEventsResponse?.nextBatch) + try rehydratedDevice.receiveEvents(events: MXTools.serialiseJSONObject(response.events)) + dehydratedDeviceEventsResponse = response + + } while !(dehydratedDeviceEventsResponse?.events.isEmpty ?? true) + } + + private func retrieveToDeviceEvents(deviceId: String, nextBatch: String?) async throws -> MXDehydratedDeviceEventsResponse { + try await withCheckedThrowingContinuation { continuation in + restClient.retrieveDehydratedDeviceEvents(forDeviceId: deviceId, nextBatch: nextBatch) { dehydratedDeviceEventsResponse in + MXLog.info("Retrieved dehydrated device events for device id: \(deviceId)") + continuation.resume(returning: dehydratedDeviceEventsResponse) + } failure: { error in + MXLog.error("Failed deleting dehydrated device", context: error) + continuation.resume(throwing: DehydrationServiceError.failedDeletingDehydratedDevice(error)) + } + } + } +} diff --git a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.h b/MatrixSDK/Crypto/Dehydration/MXDehydrationService.h deleted file mode 100644 index cd7d6f5983..0000000000 --- a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright 2021 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import - -@class MXLegacyCrossSigning; -@class MXRestClient; -@class MXExportedOlmDevice; - -NS_ASSUME_NONNULL_BEGIN - -/// Error domain for this class. -FOUNDATION_EXPORT NSString *const MXDehydrationServiceErrorDomain; - -typedef NS_ENUM(NSInteger, MXDehydrationServiceErrorCode) -{ - MXDehydrationServiceAlreadyRuningErrorCode, - MXDehydrationServiceNothingToRehydrateErrorCode, - MXDehydrationServiceAlreadyClaimedErrorCode, -}; - -/** - Service in charge of dehydrating and rehydrating a device. - - @see https://github.com/uhoreg/matrix-doc/blob/dehydration/proposals/2697-device-dehydration.md for more details - */ -@interface MXDehydrationService : NSObject - -/** - Dehydrate a new device for the current account - - @param restClient client used to call the dehydration API - @param crossSigning cross signing used to self sign the dehydrated device - @param dehydrationKey key used to pickle the Olm account - @param success callback called in case of success - @param failure callback called in case of unexpected failure - */ -- (void)dehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient - crossSigning:(MXLegacyCrossSigning *)crossSigning - dehydrationKey:(NSData*)dehydrationKey - success:(void (^)(NSString * deviceId))success - failure:(void (^)(NSError *error))failure; - -/** - Rehydrate the dehydrated device of the current acount - - @param restClient client used to call the dehydration API - @param dehydrationKey key used to unpickle the Olm account - @param success callback called in case of success - @param failure callback called in case of unexpected failure - */ -- (void)rehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient - dehydrationKey:(NSData*)dehydrationKey - success:(void (^)(NSString * deviceId))success - failure:(void (^)(NSError *error))failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m b/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m deleted file mode 100644 index 7b440b2a8d..0000000000 --- a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m +++ /dev/null @@ -1,282 +0,0 @@ -// -// Copyright 2021 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import "MXDehydrationService.h" -#import -#import "MXCrypto.h" -#import "MXCrypto_private.h" -#import "MXCryptoTools.h" -#import "MXKeyProvider.h" -#import "MXCrossSigning_Private.h" -#import "MXRawDataKey.h" -#import "MXSession.h" -#import "MXKey.h" - -NSString *const MXDehydrationAlgorithm = @"org.matrix.msc2697.v1.olm.libolm_pickle"; -NSString *const MXDehydrationServiceErrorDomain = @"org.matrix.sdk.dehydration.service"; - -@interface MXDehydrationService () - -@property (nonatomic, assign) BOOL inProgress; - -@end - -@implementation MXDehydrationService - -- (void)dehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient - crossSigning:(MXLegacyCrossSigning *)crossSigning - dehydrationKey:(NSData*)dehydrationKey - success:(void (^)( NSString * deviceId))success - failure:(void (^)(NSError *error))failure; -{ - if (self.inProgress) - { - MXLogDebug(@"[MXDehydrationService] dehydrateDevice: Dehydration already in progress -- not starting new dehydration"); - NSError *error = [NSError errorWithDomain:MXDehydrationServiceErrorDomain - code:MXDehydrationServiceAlreadyRuningErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: @"Dehydration already in progress -- not starting new dehydration", - }]; - failure(error); - return; - } - - self.inProgress = YES; - - OLMAccount *account = [[OLMAccount alloc] initNewAccount]; - NSDictionary *e2eKeys = [account identityKeys]; - - NSUInteger maxKeys = [account maxOneTimeKeys]; - [account generateOneTimeKeys:maxKeys / 2]; - - [account generateFallbackKey]; - - MXLogDebug(@"[MXDehydrationService] dehydrateDevice: Account created %@", account.identityKeys); - - // Dehydrate the account and store it into the server - NSError *error = nil; - MXDehydratedDevice *dehydratedDevice = [MXDehydratedDevice new]; - dehydratedDevice.account = [account serializeDataWithKey:dehydrationKey error:&error]; - dehydratedDevice.algorithm = MXDehydrationAlgorithm; - - if (error) - { - MXLogErrorDetails(@"[MXDehydrationService] dehydrateDevice: Account serialization failed", @{ - @"error": error ?: @"unknown" - }); - [self stopProgress]; - failure(error); - return; - } - - MXWeakify(restClient); - MXWeakify(self); - [restClient setDehydratedDevice:dehydratedDevice withDisplayName:@"Backup device" success:^(NSString *deviceId) { - MXStrongifyAndReturnIfNil(self); - MXStrongifyAndReturnIfNil(restClient); - MXLogDebug(@"[MXDehydrationService] dehydrateDevice: Preparing device keys for device %@ (current device ID %@)", deviceId, restClient.credentials.deviceId); - MXDeviceInfo *deviceInfo = [[MXDeviceInfo alloc] initWithDeviceId:deviceId]; - deviceInfo.userId = restClient.credentials.userId; - deviceInfo.keys = @{ - [NSString stringWithFormat:@"%@:%@", kMXKeyEd25519Type, deviceId]: e2eKeys[kMXKeyEd25519Type], - [NSString stringWithFormat:@"%@:%@", kMXKeyCurve25519Type, deviceId]: e2eKeys[kMXKeyCurve25519Type] - }; - deviceInfo.algorithms = [[MXCryptoAlgorithms sharedAlgorithms] supportedAlgorithms]; - - // Cross sign and device sign together so that the new session gets automatically validated on upload - MXWeakify(self); - [crossSigning signObject:deviceInfo.signalableJSONDictionary withKeyType:MXCrossSigningKeyType.selfSigning success:^(NSDictionary *signedObject) { - MXStrongifyAndReturnIfNil(self); - - NSMutableDictionary *signatures = [NSMutableDictionary dictionary]; - [signatures addEntriesFromDictionary:signedObject[@"signatures"][restClient.credentials.userId]]; - - NSString *deviceSignature = [account signMessage:[MXCryptoTools canonicalJSONDataForJSON:deviceInfo.signalableJSONDictionary]]; - signatures[[NSString stringWithFormat:@"%@:%@", kMXKeyEd25519Type, deviceInfo.deviceId]] = deviceSignature; - - deviceInfo.signatures = @{restClient.credentials.userId : signatures}; - - [self uploadDeviceInfo:deviceInfo forAccount:account withMatrixRestClient:restClient success:success failure:failure]; - } failure:^(NSError *error) { - MXLogWarning(@"[MXDehydrationService] dehydrateDevice: Failed cross-signing dehydrated device data: %@", error); - failure(error); - }]; - } failure:^(NSError *error) { - [self stopProgress]; - MXLogErrorDetails(@"[MXDehydrationService] dehydrateDevice: Failed pushing dehydrated device data", @{ - @"error": error ?: @"unknown" - }); - failure(error); - }]; -} - -- (void)rehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient - dehydrationKey:(NSData*)dehydrationKey - success:(void (^)(NSString * deviceId))success - failure:(void (^)(NSError *error))failure; -{ - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: Getting dehydrated device."); - [restClient getDehydratedDeviceWithSuccess:^(MXDehydratedDevice *device) { - if (!device || !device.deviceId) - { - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: No dehydrated device found."); - NSError *error = [NSError errorWithDomain:MXDehydrationServiceErrorDomain - code:MXDehydrationServiceNothingToRehydrateErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: @"No dehydrated device found.", - }]; - failure(error); - return; - } - - if (![device.algorithm isEqual:MXDehydrationAlgorithm]) - { - MXLogError(@"[MXDehydrationService] rehydrateDevice: Invalid dehydrated device algorithm."); - failure([NSError errorWithDomain:MXDehydrationServiceErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Wrong algorithm for dehydrated device"}]); - return; - } - - [restClient claimDehydratedDeviceWithId:device.deviceId Success:^(BOOL isClaimed) { - if (!isClaimed) - { - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: Device already claimed."); - NSError *error = [NSError errorWithDomain:MXDehydrationServiceErrorDomain - code:MXDehydrationServiceAlreadyClaimedErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: @"device already claimed.", - }]; - failure(error); - return; - } - - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: Exporting dehydrated device %@", device.deviceId); - MXCredentials *tmpCredentials = [restClient.credentials copy]; - tmpCredentials.deviceId = device.deviceId; - [MXLegacyCrypto rehydrateExportedOlmDevice:[[MXExportedOlmDevice alloc] initWithAccount:device.account pickleKey:dehydrationKey forSessions:@[]] withCredentials:tmpCredentials complete:^(BOOL stored) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (stored) - { - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: Successfully rehydrated device %@", device.deviceId); - success(device.deviceId); - } - else - { - MXLogError(@"[MXDehydrationService] rehydrateDevice: Failed storing the exported Olm device"); - failure([NSError errorWithDomain:MXDehydrationServiceErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Failed to store the exported Olm device"}]); - } - }); - }]; - } failure:^(NSError *error) { - MXLogErrorDetails(@"[MXDehydrationService] rehydrateDevice: Claiming dehydrated device failed", @{ - @"error": error ?: @"unknown" - }); - failure(error); - }]; - } failure:^(NSError *error) { - MXError *mxError = [[MXError alloc] initWithNSError:error]; - if (mxError && [mxError.errcode isEqualToString:kMXErrCodeStringNotFound]) - { - MXLogDebug(@"[MXDehydrationService] rehydrateDevice: No dehydrated device found."); - NSError *error = [NSError errorWithDomain:MXDehydrationServiceErrorDomain - code:MXDehydrationServiceNothingToRehydrateErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: @"No dehydrated device found.", - }]; - failure(error); - } - else - { - MXLogErrorDetails(@"[MXDehydrationService] rehydrateDevice: DehydratedDeviceId failed", @{ - @"error": error ?: @"unknown" - }); - failure(error); - } - }]; -} - -#pragma mark - Private methods - -- (void)uploadDeviceInfo:(MXDeviceInfo*)deviceInfo - forAccount:(OLMAccount*)account - withMatrixRestClient:(MXRestClient*)restClient - success:(void (^)(NSString *deviceId))success - failure:(void (^)(NSError *error))failure -{ - MXLogDebug(@"[MXDehydrationService] uploadDeviceInfo: preparing one time keys"); - - NSDictionary *oneTimeKeys = [self signKeys:account.oneTimeKeys - withAccount:account - userId:restClient.credentials.userId - deviceId:deviceInfo.deviceId]; - - MXLogDebug(@"[MXDehydrationService] uploadDeviceInfo: preparing fallback keys"); - - NSDictionary *fallbackKeys = [self signKeys:account.fallbackKey - withAccount:account - userId:restClient.credentials.userId - deviceId:deviceInfo.deviceId]; - - MXWeakify(self); - [restClient uploadKeys:deviceInfo.JSONDictionary oneTimeKeys:oneTimeKeys fallbackKeys:fallbackKeys forDeviceWithId:deviceInfo.deviceId success:^(MXKeysUploadResponse *keysUploadResponse) { - [account markOneTimeKeysAsPublished]; - MXLogDebug(@"[MXDehydrationService] uploadDeviceInfo: dehydration done successfully with device ID: %@ ed25519: %@ curve25519: %@", deviceInfo.deviceId, account.identityKeys[kMXKeyEd25519Type], account.identityKeys[kMXKeyCurve25519Type]); - MXStrongifyAndReturnIfNil(self); - [self stopProgress]; - success(deviceInfo.deviceId); - } failure:^(NSError *error) { - MXLogErrorDetails(@"[MXDehydrationService] uploadDeviceInfo: failed uploading device keys", @{ - @"error": error ?: @"unknown" - }); - MXStrongifyAndReturnIfNil(self); - [self stopProgress]; - failure(error); - }]; -} - -#pragma mark - Private methods - -- (void)stopProgress -{ - self.inProgress = NO; -} - -- (NSDictionary *)signKeys:(NSDictionary *)keys - withAccount:(OLMAccount *)account - userId:(NSString *)userId - deviceId:(NSString *)deviceId - -{ - NSMutableDictionary *signedKeys = [NSMutableDictionary dictionary]; - - for (NSString *keyId in keys[kMXKeyCurve25519Type]) - { - NSMutableDictionary *key = [NSMutableDictionary dictionary]; - key[@"key"] = keys[kMXKeyCurve25519Type][keyId]; - - NSString *signature = [account signMessage:[MXCryptoTools canonicalJSONDataForJSON:key]]; - key[@"signatures"] = @{ - userId: @{ - [NSString stringWithFormat:@"%@:%@", kMXKeyEd25519Type, deviceId]: signature - } - }; - - signedKeys[[NSString stringWithFormat:@"%@:%@", kMXKeySignedCurve25519Type, keyId]] = key; - } - - return signedKeys; -} - -@end diff --git a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.h b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.h index cb96df857b..700c31c5fb 100644 --- a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.h +++ b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.h @@ -31,7 +31,7 @@ extern const struct MXSecretId { __unsafe_unretained NSString *crossSigningSelfSigning; __unsafe_unretained NSString *crossSigningUserSigning; __unsafe_unretained NSString *keyBackup; - + __unsafe_unretained NSString *dehydratedDevice; } MXSecretId; diff --git a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m index e17b319c8d..724a1363c0 100644 --- a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m +++ b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m @@ -30,7 +30,8 @@ .crossSigningMaster = @"m.cross_signing.master", .crossSigningSelfSigning = @"m.cross_signing.self_signing", .crossSigningUserSigning = @"m.cross_signing.user_signing", - .keyBackup = @"m.megolm_backup.v1" + .keyBackup = @"m.megolm_backup.v1", + .dehydratedDevice = @"org.matrix.msc3814" // @"m.dehydrated_device" }; diff --git a/MatrixSDK/Crypto/MXCrypto.h b/MatrixSDK/Crypto/MXCrypto.h index d638850b0d..3f12cdd45f 100644 --- a/MatrixSDK/Crypto/MXCrypto.h +++ b/MatrixSDK/Crypto/MXCrypto.h @@ -40,6 +40,7 @@ @class MXSession; @class MXRoom; +@class DehydrationService; NS_ASSUME_NONNULL_BEGIN @@ -114,6 +115,8 @@ extern NSString *const MXDeviceListDidUpdateUsersDevicesNotification; */ @property (nonatomic, readonly) MXRecoveryService *recoveryService; +@property (nonatomic, readonly) DehydrationService *dehydrationService; + #pragma mark - Crypto start / close /** diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index e111cfc0a2..5e77f81a30 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -156,8 +156,8 @@ @implementation MXLegacyCrypto __block id crypto; #ifdef MX_CRYPTO - dispatch_queue_t cryptoQueue = [MXLegacyCrypto dispatchQueueForUser:mxSession.matrixRestClient.credentials.userId]; - dispatch_sync(cryptoQueue, ^{ + dispatch_queue_t cryptoQueue = [MXLegacyCrypto dispatchQueueForUser:mxSession.matrixRestClient.credentials.userId]; + dispatch_sync(cryptoQueue, ^{ MXCryptoStoreClass *cryptoStore = [MXCryptoStoreClass createStoreWithCredentials:mxSession.matrixRestClient.credentials]; cryptoStore.cryptoVersion = MXCryptoVersionLast; @@ -174,7 +174,7 @@ + (void)initializeCryptoWithMatrixSession:(MXSession *)mxSession complete:(void (^)(id crypto, NSError *error))complete { #ifdef MX_CRYPTO - [self initalizeLegacyCryptoWithMatrixSession:mxSession complete:complete]; + [self initalizeLegacyCryptoWithMatrixSession:mxSession complete:complete]; #else complete(nil); #endif diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index f700e7fd6d..2e5c642b7d 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -60,6 +60,7 @@ class MXCryptoV2: NSObject, MXCrypto { let keyVerificationManager: MXKeyVerificationManager let crossSigning: MXCrossSigning let recoveryService: MXRecoveryService + let dehydrationService: DehydrationService @MainActor init( @@ -124,14 +125,13 @@ class MXCryptoV2: NSObject, MXCrypto { ) crossSigning = crossSign + let secretStorage = MXSecretStorage(matrixSession: session, processingQueue: legacyQueue) + recoveryService = MXRecoveryService( dependencies: .init( credentials: restClient.credentials, backup: backup, - secretStorage: MXSecretStorage( - matrixSession: session, - processingQueue: legacyQueue - ), + secretStorage: secretStorage, secretStore: MXCryptoSecretStoreV2( backup: backup, backupEngine: backupEngine, @@ -143,6 +143,10 @@ class MXCryptoV2: NSObject, MXCrypto { delegate: crossSign ) + dehydrationService = DehydrationService(restClient: restClient, + secretStorage: secretStorage, + dehydratedDevices: machine.dehydratedDevices()) + log.debug("Initialized Crypto module") } @@ -330,7 +334,8 @@ class MXCryptoV2: NSObject, MXCrypto { toDevice: syncResponse.toDevice, deviceLists: syncResponse.deviceLists, deviceOneTimeKeysCounts: syncResponse.deviceOneTimeKeysCount ?? [:], - unusedFallbackKeys: syncResponse.unusedFallbackKeys + unusedFallbackKeys: syncResponse.unusedFallbackKeys, + nextBatchToken: syncResponse.nextBatch ) await handle(toDeviceEvents: toDevice.events) } catch { @@ -382,18 +387,37 @@ class MXCryptoV2: NSObject, MXCrypto { case .verified: // If we want to set verified status, we will manually verify the device, // including uploading relevant signatures + try? machine.setLocalTrust(userId: machine.userId, deviceId: deviceId, trust: .verified) - Task { - do { - try await machine.verifyDevice(userId: userId, deviceId: deviceId) - log.debug("Successfully marked device as verified") - await MainActor.run { - success?() + if (userId == machine.userId) { + if (machine.crossSigningStatus().hasSelfSigning) { + // If we can cross sign, upload a new signature for that device + Task { + do { + try await machine.verifyDevice(userId: userId, deviceId: deviceId) + log.debug("Successfully marked device as verified") + await MainActor.run { + success?() + } + } catch { + log.error("Failed marking device as verified", context: error) + await MainActor.run { + failure?(error) + } + } } - } catch { - log.error("Failed marking device as verified", context: error) - await MainActor.run { - failure?(error) + } else { + // It's a good time to request secrets + Task { + do { + try await machine.queryMissingSecretsFromOtherSessions() + await MainActor.run { + success?() + } + } catch { + log.error("Failed to query missing secrets", context: error) + failure?(error) + } } } } diff --git a/MatrixSDK/Crypto/MXCryptoV2Factory.swift b/MatrixSDK/Crypto/MXCryptoV2Factory.swift index 4d32bd4495..d910a1dc7a 100644 --- a/MatrixSDK/Crypto/MXCryptoV2Factory.swift +++ b/MatrixSDK/Crypto/MXCryptoV2Factory.swift @@ -16,6 +16,16 @@ import Foundation +/// Delegate for migrating account data from legacy crypto to rust-based Crypto SDK +@objc public protocol MXCryptoV2MigrationDelegate { + + /// Flag indicating whether this account requires a re-verification after migrating to Crypto SDK + /// + /// This flag is set to true if the legacy account is considered verified but the rust account + /// does not consider the migrated data secure enough, as it applies stricter security conditions. + var needsVerificationUpgrade: Bool { get set } +} + @objc public class MXCryptoV2Factory: NSObject { enum Error: Swift.Error { case cryptoNotAvailable @@ -28,6 +38,21 @@ import Foundation .deprecated3 } + @objc public func hasCryptoData(for session: MXSession!) -> Bool { + guard let userId = session?.myUserId else { + log.error("Missing required dependencies") + return false + } + + do { + let url = try MXCryptoMachineStore.storeURL(for: userId) + return FileManager.default.fileExists(atPath: url.path) + } catch { + log.error("Failed creating url for user", context: error) + return false + } + } + @objc public func buildCrypto( session: MXSession!, migrationProgress: ((Double) -> Void)?, @@ -124,7 +149,7 @@ import Foundation // unless the rust-based crypto already considers the current session to be verified given // the migration data log.debug("Needs verification upgrade") - MXSDKOptions.sharedInstance().cryptoSDKFeature?.needsVerificationUpgrade = true + MXSDKOptions.sharedInstance().cryptoMigrationDelegate?.needsVerificationUpgrade = true } } } diff --git a/MatrixSDK/Crypto/MXCryptoV2Feature.swift b/MatrixSDK/Crypto/MXCryptoV2Feature.swift deleted file mode 100644 index 5fc1d4d6de..0000000000 --- a/MatrixSDK/Crypto/MXCryptoV2Feature.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2023 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -/// Feature representing the availability of the external rust-based Crypto SDK -/// whilst it is not fully available to everyone and / or is an optional feature. -@objc public protocol MXCryptoV2Feature { - /// Is Crypto SDK currently enabled - /// - /// By default this value is `false`. Once enabled, it can only be disabled by logging out, - /// as there is no way to migrate from from Crypto SDK back to legacy crypto. - var isEnabled: Bool { get } - - /// Flag indicating whether this account requires a re-verification after migrating to Crypto SDK - /// - /// This flag is set to true if the legacy account is considered verified but the rust account - /// does not consider the migrated data secure enough, as it applies stricter security conditions. - var needsVerificationUpgrade: Bool { get set } - - /// Manually enable the feature - /// - /// This is typically triggered by some user settings / Labs as an experimental feature. Once called - /// it should restart the session to re-initialize the crypto module. - func enable() - - /// Try to enable the feature for a given user - /// - /// This method should only be called when initializing a crypto module (e.g. during app launch or login), - /// as it is not possible to swap out crypto modules whilst a session is active. - /// - /// The availability conditions are implementation details, typically consisting of - /// various feature flags. - /// - /// If available, this method will set `isEnabled` permanently to `true`. - func enableIfAvailable(forUserId userId: String!) -} diff --git a/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift b/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift index 6465ee00d9..741ea8ed56 100644 --- a/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift +++ b/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift @@ -54,9 +54,9 @@ struct MXCryptoMigrationStore { account: try pickledAccount(pickleKey: pickleKey), sessions: [], // Sessions are extracted in batches separately inboundGroupSessions: [], // Group sessions are extracted in batches separately + pickleKey: [UInt8](pickleKey), backupVersion: legacyStore.backupVersion, backupRecoveryKey: backupRecoveryKey(), - pickleKey: [UInt8](pickleKey), crossSigning: crossSigning(), trackedUsers: trackedUsers(), roomSettings: extractRoomSettings() diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m index ff11f6e77c..ff444a76cc 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m @@ -58,8 +58,10 @@ - (instancetype)initWithDependencies:(MXRecoveryServiceDependencies *)dependenci MXSecretId.crossSigningSelfSigning, MXSecretId.crossSigningUserSigning, MXSecretId.keyBackup, + MXSecretId.dehydratedDevice ]; } + return self; } @@ -690,7 +692,6 @@ - (void)recoverServicesAssociatedWithSecrets:(nullable NSArray*)secre }); } - - (void)recoverKeyBackupWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failure { diff --git a/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2.swift b/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2.swift index 5974c44354..183c75504e 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2.swift +++ b/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2.swift @@ -103,7 +103,7 @@ class MXQRCodeTransactionV2: NSObject, MXQRCodeTransaction { log.debug("->") let data = MXQRCodeDataCoder().encode(otherQRCodeData) - let string = MXBase64Tools.base64(from: data) + let string = MXBase64Tools.unpaddedBase64(from: data) guard let result = request.scanQrCode(data: string) else { log.failure("Failed scanning QR code") return diff --git a/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m b/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m index cf9dabcaad..300ab9934a 100644 --- a/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m +++ b/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m @@ -142,8 +142,6 @@ - (void)initialiseState:(NSArray *)stateEvents - (void)destroy { - [room.mxSession resetReplayAttackCheckInTimeline:_timelineId]; - if (httpOperation) { // Cancel the current server request @@ -190,8 +188,6 @@ - (BOOL)canPaginate:(MXTimelineDirection)direction - (void)resetPagination { - [room.mxSession resetReplayAttackCheckInTimeline:_timelineId]; - // Reset the back state to the current room state backState = [[MXRoomState alloc] initBackStateWith:_state]; @@ -203,8 +199,6 @@ - (MXHTTPOperation *)resetPaginationAroundInitialEventWithLimit:(NSUInteger)limi { NSParameterAssert(success); NSAssert(_initialEventId, @"[MXRoomEventTimeline] resetPaginationAroundInitialEventWithLimit cannot be called on live timeline"); - - [room.mxSession resetReplayAttackCheckInTimeline:_timelineId]; // Reset the store if (!store.isPermanent) diff --git a/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift b/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift index b5fada9a90..f3b0c1e380 100644 --- a/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift +++ b/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift @@ -99,8 +99,6 @@ public class MXThreadEventTimeline: NSObject, MXEventTimeline { } public func destroy() { - thread.session?.resetReplayAttackCheck(inTimeline: timelineId) - removeAllListeners() currentHttpOperation?.cancel() @@ -132,8 +130,6 @@ public class MXThreadEventTimeline: NSObject, MXEventTimeline { } public func resetPagination() { - thread.session?.resetReplayAttackCheck(inTimeline: timelineId) - // Reset store pagination storeMessagesEnumerator = store.messagesEnumerator(forRoom: thread.roomId) @@ -150,8 +146,6 @@ public class MXThreadEventTimeline: NSObject, MXEventTimeline { fatalError("[MXThreadEventTimeline][\(timelineId)] resetPaginationAroundInitialEventWithLimit cannot be called on live timeline") } - thread.session?.resetReplayAttackCheck(inTimeline: timelineId) - // Reset the store if !store.isPermanent { store.deleteAllData() diff --git a/MatrixSDK/Data/MXRoom.m b/MatrixSDK/Data/MXRoom.m index 108ec38ce3..07809b8863 100644 --- a/MatrixSDK/Data/MXRoom.m +++ b/MatrixSDK/Data/MXRoom.m @@ -81,11 +81,6 @@ The list of room operations (sending of text, images...) that must be sent FIFO queue of failure blocks waiting for [self members:]. */ NSMutableArray *pendingMembersFailureBlocks; - - /** - The manager for sharing keys of messages with invited users - */ - MXSharedHistoryKeyManager *sharedHistoryKeyManager; } @end @@ -122,14 +117,6 @@ - (id)initWithRoomId:(NSString *)roomId matrixSession:(MXSession *)mxSession2 an { _roomId = roomId; mxSession = mxSession2; - - if ([mxSession.crypto isKindOfClass:[MXLegacyCrypto class]]) - { - MXMegolmDecryption *decryption = [[MXMegolmDecryption alloc] initWithCrypto:mxSession.crypto]; - sharedHistoryKeyManager = [[MXSharedHistoryKeyManager alloc] initWithRoomId:roomId - crypto:mxSession.crypto - service:decryption]; - } if (store) { @@ -1026,7 +1013,7 @@ - (MXHTTPOperation*)sendImage:(NSData*)imageData kMXMessageBodyKey: filename, @"url": fakeMediaURI, @"info": [@{ - @"mimetype": mimetype, + @"mimetype": (mimetype ?: @"application/octet-stream"), @"w": @(imageSize.width), @"h": @(imageSize.height), @"size": @(imageData.length) @@ -1353,7 +1340,7 @@ - (MXHTTPOperation*)sendVideoAsset:(AVAsset*)videoAsset } // update metadata with result of converter output - msgContent[@"info"][@"mimetype"] = mimetype; + msgContent[@"info"][@"mimetype"] = (mimetype ?: @"application/octet-stream"); msgContent[@"info"][@"w"] = @(size.width); msgContent[@"info"][@"h"] = @(size.height); msgContent[@"info"][@"duration"] = @((int)floor(durationInMs)); @@ -1676,7 +1663,7 @@ - (MXHTTPOperation*)_sendFile:(NSURL*)fileLocalURL kMXMessageBodyKey: filename, @"url": fakeMediaURI, @"info": @{ - @"mimetype": mimeType, + @"mimetype": (mimeType ?: @"application/octet-stream"), @"size": @(fileData.length) }, kMXMessageContentKeyExtensibleTextMSC1767: filename, @@ -1684,7 +1671,7 @@ - (MXHTTPOperation*)_sendFile:(NSURL*)fileLocalURL kMXMessageContentKeyExtensibleFileSize: @(fileData.length), kMXMessageContentKeyExtensibleFileName: filename, kMXMessageContentKeyExtensibleFileURL: fakeMediaURI, - kMXMessageContentKeyExtensibleFileMimeType: mimeType + kMXMessageContentKeyExtensibleFileMimeType: (mimeType ?: @"application/octet-stream") }.mutableCopy}.mutableCopy; if(additionalTypes.count) @@ -1970,24 +1957,9 @@ - (MXHTTPOperation*)inviteUser:(NSString*)userId success:(void (^)(void))success failure:(void (^)(NSError *error))failure { - if (MXSDKOptions.sharedInstance.enableRoomSharedHistoryOnInvite) - { - [self shareRoomKeysWith:userId]; - } return [mxSession.matrixRestClient inviteUser:userId toRoom:self.roomId success:success failure:failure]; } -- (void)shareRoomKeysWith:(NSString *)userId -{ - // The value of 20 is arbitrary and imprecise, we merely want to ensure that when a user is invited to a room - // they are able to read any immediately preciding messages that may be relevant to the invite. - NSInteger numberOfSharedMessage = 20; - id enumerator = [self enumeratorForStoredMessagesWithTypeIn:@[kMXEventTypeStringRoomMessage]]; - [sharedHistoryKeyManager shareMessageKeysWithUserId:userId - messageEnumerator:enumerator - limit:numberOfSharedMessage]; -} - - (MXHTTPOperation*)inviteUserByEmail:(NSString*)email success:(void (^)(void))success failure:(void (^)(NSError *error))failure diff --git a/MatrixSDK/Data/MXRoomState.m b/MatrixSDK/Data/MXRoomState.m index e398d95cd0..a97bcf0ed1 100644 --- a/MatrixSDK/Data/MXRoomState.m +++ b/MatrixSDK/Data/MXRoomState.m @@ -120,23 +120,31 @@ + (void)loadRoomStateFromStore:(id)store { [store stateOfRoom:roomId success:^(NSArray * _Nonnull stateEvents) { if (!stateEvents.count) { - MXLogWarning(@"[MXRoomState] loadRoomStateFromStore(%@): No state events stored, loading from api", logId); + MXLogWarning(@"[MXRoomState] loadRoomStateFromStore(%@): No state events stored, loading from API", logId); - [matrixSession.matrixRestClient stateOfRoom:roomId success:^(NSArray *JSONData) { - NSArray *events = [MXEvent modelsFromJSON:JSONData]; - MXLogDebug(@"[MXRoomState] loadRoomStateFromStore(%@): Loaded %lu events from api", logId, events.count); - - [roomState handleStateEvents:events]; - onComplete(roomState); - } failure:^(NSError *error) { - NSDictionary *details = @{ - @"log_id": logId ?: @"unknown", - @"error": error ?: @"unknown" - }; - MXLogErrorDetails(@"[MXRoomState] loadRoomStateFromStore: Failed to load any events from api", details); - + if (!matrixSession) + { + MXLogError(@"[MXRoomState] loadRoomStateFromStore: Missing session, unable to load from API") onComplete(roomState); - }]; + } + else + { + [matrixSession.matrixRestClient stateOfRoom:roomId success:^(NSArray *JSONData) { + NSArray *events = [MXEvent modelsFromJSON:JSONData]; + MXLogDebug(@"[MXRoomState] loadRoomStateFromStore(%@): Loaded %lu events from api", logId, events.count); + + [roomState handleStateEvents:events]; + onComplete(roomState); + } failure:^(NSError *error) { + NSDictionary *details = @{ + @"log_id": logId ?: @"unknown", + @"error": error ?: @"unknown" + }; + MXLogErrorDetails(@"[MXRoomState] loadRoomStateFromStore: Failed to load any events from API", details); + + onComplete(roomState); + }]; + } } else { MXLogDebug(@"[MXRoomState] loadRoomStateFromStore(%@): Initializing with %lu state events", logId, stateEvents.count); diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 3c3838c19d..e7b6ab5f51 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -2205,7 +2205,23 @@ - (void)saveReceipts // Store new data [self checkFolderExistenceForRoom:roomId forBackup:NO]; - [NSKeyedArchiver archiveRootObject:receiptsStore toFile:file]; + + NSError *error = nil; + NSData *result = [NSKeyedArchiver archivedDataWithRootObject:receiptsStore requiringSecureCoding:false error:&error]; + + if (error != nil) + { + MXLogErrorDetails(@"Failed archiving receipts store", error); + continue; + } + + [result writeToURL:[NSURL fileURLWithPath:file] options: NSDataWritingAtomic error: &error]; + + if (error != nil) + { + MXLogErrorDetails(@"Failed writing receipts store to file", error); + continue; + } } } } @@ -2400,8 +2416,8 @@ - (NSArray*)filesAtPath:(NSString*)path NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL URLWithString:path] - includingPropertiesForKeys:nil - options:0 + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:NSDirectoryEnumerationProducesRelativePathURLs errorHandler:^(NSURL *url, NSError *error) { return YES; }]; @@ -2414,11 +2430,7 @@ - (NSArray*)filesAtPath:(NSString*)path if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && ![isDirectory boolValue]) { // Return a file path relative to 'path' - NSRange range = [url.absoluteString rangeOfString:path]; - NSString *relativeFilePath = [url.absoluteString - substringFromIndex:(range.location + range.length)]; - - [files addObject:relativeFilePath]; + [files addObject:[@"/" stringByAppendingString: url.relativeString]]; } } diff --git a/MatrixSDK/JSONModels/Aggregations/MXAggregationPaginatedResponse.m b/MatrixSDK/JSONModels/Aggregations/MXAggregationPaginatedResponse.m index 19625d7d65..576e5327d4 100644 --- a/MatrixSDK/JSONModels/Aggregations/MXAggregationPaginatedResponse.m +++ b/MatrixSDK/JSONModels/Aggregations/MXAggregationPaginatedResponse.m @@ -35,12 +35,20 @@ + (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary MXAggregationPaginatedResponse *paginatedResponse; NSArray *chunk; - MXJSONModelSetMXJSONModelArray(chunk, MXEvent.class, JSONDictionary[@"chunk"]) - + NSArray *chunkJson = JSONDictionary[@"chunk"]; + + // For some reason modelsFromJSON returns nil if you pass it an empty array. + // In this case we want an empty array or we get an error. + if([chunkJson isKindOfClass:NSArray.class] && chunkJson.count == 0) + { + chunk = @[]; + } else { + MXJSONModelSetMXJSONModelArray(chunk, MXEvent.class, chunkJson) + } + if (chunk) { paginatedResponse = [MXAggregationPaginatedResponse new]; - paginatedResponse->_chunk = chunk; MXJSONModelSetString(paginatedResponse->_nextBatch, JSONDictionary[@"next_batch"]) diff --git a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.h b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.h index b4a5d5ab3d..50ade7611a 100644 --- a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.h +++ b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.h @@ -20,6 +20,7 @@ #import "MXWellKnownBaseConfig.h" #import "MXWellknownIntegrations.h" #import "MXWellKnownTileServerConfig.h" +#import "MXWellKnownAuthentication.h" NS_ASSUME_NONNULL_BEGIN @@ -45,6 +46,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable) MXWellKnownTileServerConfig *tileServer; +@property (nonatomic, nullable) MXWellKnownAuthentication *authentication; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.m b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.m index fd4fde1686..181418d603 100644 --- a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.m +++ b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnown.m @@ -23,6 +23,8 @@ static NSString *const kMXTileServerKey = @"m.tile_server"; static NSString *const kMXTileServerMSC3488Key = @"org.matrix.msc3488.tile_server"; +static NSString *const kMXAuthenticationKey = @"org.matrix.msc2965.authentication"; + @interface MXWellKnown() { // The original dictionary to store extented data @@ -46,6 +48,7 @@ + (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary MXJSONModelSetMXJSONModel(wellknown.identityServer, MXWellKnownBaseConfig, JSONDictionary[kMXIdentityServerKey]); MXJSONModelSetMXJSONModel(wellknown.integrations, MXWellknownIntegrations, JSONDictionary[kMXIntegrationsKey]); + MXJSONModelSetMXJSONModel(wellknown.authentication, MXWellKnownAuthentication, JSONDictionary[kMXAuthenticationKey]) if (JSONDictionary[kMXTileServerKey]) { @@ -84,6 +87,7 @@ - (id)initWithCoder:(NSCoder *)aDecoder _identityServer = [aDecoder decodeObjectForKey:kMXIdentityServerKey]; _integrations = [aDecoder decodeObjectForKey:kMXIntegrationsKey]; _tileServer = [aDecoder decodeObjectForKey:kMXTileServerKey]; + _authentication = [aDecoder decodeObjectForKey:kMXAuthenticationKey]; JSONDictionary = [aDecoder decodeObjectForKey:@"JSONDictionary"]; } return self; @@ -95,6 +99,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder [aCoder encodeObject:_identityServer forKey:kMXIdentityServerKey]; [aCoder encodeObject:_integrations forKey:kMXIntegrationsKey]; [aCoder encodeObject:_tileServer forKey:kMXTileServerKey]; + [aCoder encodeObject:_authentication forKey:kMXAuthenticationKey]; [aCoder encodeObject:JSONDictionary forKey:@"JSONDictionary"]; } diff --git a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.h b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.h new file mode 100644 index 0000000000..9c483c65e9 --- /dev/null +++ b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.h @@ -0,0 +1,40 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +#import "MXJSONModel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + MSC2965: OIDC Authentication + "org.matrix.msc2965.authentication": { + "issuer": "https://example.com/", + "account": "https://example.com/account" + } + */ + +@interface MXWellKnownAuthentication : MXJSONModel + +@property (nonatomic, readonly) NSString *issuer; +@property (nonatomic, readonly, nullable) NSString *account; + +-(NSURL * _Nullable) getLogoutDeviceURLFromID: (NSString * ) deviceID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.m b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.m new file mode 100644 index 0000000000..fe2cdbdf6a --- /dev/null +++ b/MatrixSDK/JSONModels/AutoDiscovery/MXWellKnownAuthentication.m @@ -0,0 +1,82 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "MXWellKnownAuthentication.h" + +static NSString *const kMXIssuer = @"issuer"; +static NSString *const kMXAccount = @"account"; + +@interface MXWellKnownAuthentication () + +@property (nonatomic, readwrite) NSString *issuer; +@property (nonatomic, readwrite, nullable) NSString *account; + +@end + +@implementation MXWellKnownAuthentication + ++ (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary +{ + MXWellKnownAuthentication *wellKnownAuthentication; + + NSString *issuer; + MXJSONModelSetString(issuer, JSONDictionary[kMXIssuer]); + + if (issuer) + { + wellKnownAuthentication = [[MXWellKnownAuthentication alloc] init]; + wellKnownAuthentication.issuer = issuer; + MXJSONModelSetString(wellKnownAuthentication.account, JSONDictionary[kMXAccount]) + } + + return wellKnownAuthentication; +} + +-(NSURL * _Nullable) getLogoutDeviceURLFromID: (NSString * ) deviceID +{ + if (!_account) + { + return nil; + } + NSURLComponents *components = [NSURLComponents componentsWithString:_account]; + components.queryItems = @[ + [NSURLQueryItem queryItemWithName:@"device_id" value:deviceID], + [NSURLQueryItem queryItemWithName:@"action" value:@"session_end"] + ]; + return components.URL; +} + + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super init]; + if (self) + { + _issuer = [aDecoder decodeObjectForKey:kMXIssuer]; + _account = [aDecoder decodeObjectForKey: kMXAccount]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:_issuer forKey:kMXIssuer]; + [aCoder encodeObject:_account forKey:kMXAccount]; +} + +@end diff --git a/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.h b/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.h index 6fbfe1e965..2aec96d6a2 100644 --- a/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.h +++ b/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.h @@ -31,6 +31,7 @@ extern NSString *const MXLoginSSOFlowIdentityProvidersKey; List of all SSO Identity Providers supported */ @property (nonatomic, readonly) NSArray *identityProviders; +@property (atomic, readonly) BOOL delegatedOIDCCompatibility; @end diff --git a/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.m b/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.m index cf6cae656c..95083abb8a 100644 --- a/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.m +++ b/MatrixSDK/JSONModels/Login/MXLoginSSOFlow.m @@ -17,10 +17,12 @@ #import "MXLoginSSOFlow.h" NSString *const MXLoginSSOFlowIdentityProvidersKey = @"identity_providers"; +NSString *const MXLoginSSOFlowDelegatedOIDCCompatibilityKey = @"org.matrix.msc3824.delegated_oidc_compatibility"; @interface MXLoginSSOFlow() @property (nonatomic, readwrite) NSArray *identityProviders; +@property (atomic, readwrite) BOOL delegatedOIDCCompatibility; @end @@ -50,6 +52,7 @@ + (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary loginFlow.identityProviders = identityProviders; + MXJSONModelSetBoolean(loginFlow.delegatedOIDCCompatibility, JSONDictionary[MXLoginSSOFlowDelegatedOIDCCompatibilityKey]); } return loginFlow; diff --git a/MatrixSDK/JSONModels/MXJSONModels.h b/MatrixSDK/JSONModels/MXJSONModels.h index c6075b3573..2a758f1f38 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.h +++ b/MatrixSDK/JSONModels/MXJSONModels.h @@ -1379,32 +1379,27 @@ FOUNDATION_EXPORT NSString *const kMXPushRuleScopeStringGlobal; @end -#pragma mark - Dehydration +#pragma mark - Device Dehydration -/** - `MXDehydratedDevice` represents the dehydrated device of the current user. - */ -@interface MXDehydratedDevice : MXJSONModel +@interface MXDehydratedDeviceCreationParameters : MXJSONModel - /** - A unique identifier of the device. - */ - @property (nonatomic) NSString *deviceId; +@property (nonatomic) NSString *body; - /** - The encrypted account data of the dehydrated device (libolm's pickle format) - */ - @property (nonatomic) NSString *account; +@end - /** - The algorithm used for encrypting the account data - */ - @property (nonatomic) NSString *algorithm; +@interface MXDehydratedDeviceResponse : MXJSONModel - /** - The passphrase used for encrypting the account data (optional) - */ - @property (nonatomic) NSString *passphrase; +@property (nonatomic, nonnull) NSString *deviceId; + +@property (nonatomic, nonnull) NSDictionary *deviceData; + +@end + +@interface MXDehydratedDeviceEventsResponse : MXJSONModel + +@property (nonatomic) NSArray *events; + +@property (nonatomic, nullable) NSString *nextBatch; @end diff --git a/MatrixSDK/JSONModels/MXJSONModels.m b/MatrixSDK/JSONModels/MXJSONModels.m index 60a3e7b82f..0052544372 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.m +++ b/MatrixSDK/JSONModels/MXJSONModels.m @@ -2165,62 +2165,37 @@ + (id)modelFromJSON:(NSDictionary *)JSONDictionary @end -#pragma mark - Dehydration +#pragma mark - Device Dehydration -@implementation MXDehydratedDevice +@implementation MXDehydratedDeviceCreationParameters : MXJSONModel -+ (id)modelFromJSON:(NSDictionary *)JSONDictionary +- (NSDictionary *)JSONDictionary { - MXDehydratedDevice *device = [[MXDehydratedDevice alloc] init]; - if (device) - { - MXJSONModelSetString(device.deviceId, JSONDictionary[@"device_id"]); - NSDictionary *deviceData = nil; - MXJSONModelSetDictionary(deviceData, JSONDictionary[@"device_data"]); - MXJSONModelSetString(device.account, deviceData[@"account"]); - MXJSONModelSetString(device.algorithm, deviceData[@"algorithm"]); - MXJSONModelSetString(device.passphrase, deviceData[@"passphrase"]); - } - - return device; + return [MXTools deserialiseJSONString:self.body]; } -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super init]; - if (self) - { - _deviceId = [aDecoder decodeObjectForKey:@"device_id"]; - _account = [aDecoder decodeObjectForKey:@"account"]; - _algorithm = [aDecoder decodeObjectForKey:@"algorithm"]; - _passphrase = [aDecoder decodeObjectForKey:@"passphrase"]; - } - return self; -} +@end -- (void)encodeWithCoder:(NSCoder *)aCoder +@implementation MXDehydratedDeviceResponse + ++ (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary { - [aCoder encodeObject:_deviceId forKey:@"device_id"]; - [aCoder encodeObject:_account forKey:@"account"]; - [aCoder encodeObject:_algorithm forKey:@"algorithm"]; - if (_passphrase) - { - [aCoder encodeObject:_passphrase forKey:@"passphrase"]; - } + MXDehydratedDeviceResponse *dehydratedDevice = [[MXDehydratedDeviceResponse alloc] init]; + MXJSONModelSetString(dehydratedDevice.deviceId, JSONDictionary[@"device_id"]); + MXJSONModelSetDictionary(dehydratedDevice.deviceData, JSONDictionary[@"device_data"]); + return dehydratedDevice; } -- (NSDictionary *)JSONDictionary +@end + +@implementation MXDehydratedDeviceEventsResponse + ++ (instancetype)modelFromJSON:(NSDictionary *)JSONDictionary { - NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:@{ - @"algorithm": self.algorithm, - @"account": self.account - }]; - - if (self.passphrase) - { - dictionary[@"passphrase"] = self.passphrase; - } - return dictionary.copy; + MXDehydratedDeviceEventsResponse *dehydratedDevice = [[MXDehydratedDeviceEventsResponse alloc] init]; + MXJSONModelSetArray(dehydratedDevice.events, JSONDictionary[@"events"]); + MXJSONModelSetString(dehydratedDevice.nextBatch, JSONDictionary[@"next_batch"]); + return dehydratedDevice; } @end diff --git a/MatrixSDK/MXRestClient.h b/MatrixSDK/MXRestClient.h index cd4fdf51d8..981c3fc992 100644 --- a/MatrixSDK/MXRestClient.h +++ b/MatrixSDK/MXRestClient.h @@ -2516,47 +2516,49 @@ Note: Clients should consider avoiding this endpoint for URLs posted in encrypte success:(void (^)(MXDeviceListResponse *deviceLists))success failure:(void (^)(NSError *error))failure; - -#pragma mark - Crypto: Dehydration +#pragma mark - Device Dehydration /** - Get the dehydrated device of the current account. - - @param success A block object called when the operation succeeds. It provides a `MXDehydratedDevice` instance of the current account. + Creates a new dehydrated device on the current user's account with the given parameters, coming out of the RustCryptoSDK + @param parameters the device data as received from the RustCryptoSDK + @param success A block object called when the operation succeeds. It provides the ID of the newly dehydrated device. @param failure A block object called when the operation fails. - @return a MXHTTPOperation instance. */ -- (MXHTTPOperation*)getDehydratedDeviceWithSuccess:(void (^)(MXDehydratedDevice *device))success - failure:(void (^)(NSError *error))failure; +- (MXHTTPOperation*)createDehydratedDevice:(MXDehydratedDeviceCreationParameters *)parameters + success:(void (^)(NSString * _Nonnull deviceId))success + failure:(void (^)(NSError * _Nonnull error))failure; /** - Set a given device as the dehydrated device of the current account. - - @param device data of the dehydrated device - @param deviceDisplayName display name of the dehydrated device - @param success A block object called when the operation succeeds. It provides the ID of the newly dehydrated device. + Get the dehydrated device of the current account. + @param success A block object called when the operation succeeds. It provides a `MXDehydratedDeviceResponse` instance of the current account. @param failure A block object called when the operation fails. - @return a MXHTTPOperation instance. - */ -- (MXHTTPOperation*)setDehydratedDevice:(MXDehydratedDevice *)device - withDisplayName:(NSString *)deviceDisplayName - success:(void (^)(NSString *deviceId))success - failure:(void (^)(NSError *error))failure; + */ +- (MXHTTPOperation*)retrieveDehydratedDeviceWithSuccess:(void (^)(MXDehydratedDeviceResponse * _Nonnull dehydratedDevice))success + failure:(void (^)(NSError * _Nonnull error))failure; /** - Claim the dehydrated device of the current account. - - @param deviceId ID of the dehydrated to be claimed. - @param success A block object called when the operation succeeds. + Delete the current dehydrated device + @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*)deleteDehydratedDeviceWithSuccess:(void (^)(void))success + failure:(void (^)(NSError * _Nonnull error))failure; +/** + Retrieves the to device events stored on the backend for the given dehydrated device. Results are batched so multiple invocations might be necessary + @param deviceId The dehydrated device id in question + @param nextBatch Pagination token for retrieving more events + @param success A block object called when the operation succeeds. It provides the events and a next batch token + @param failure A block object called when the operation fails. @return a MXHTTPOperation instance. - */ -- (MXHTTPOperation*)claimDehydratedDeviceWithId:(NSString*)deviceId - Success:(void (^)(BOOL success))success - failure:(void (^)(NSError *error))failure; + */ +- (MXHTTPOperation*)retrieveDehydratedDeviceEventsForDeviceId:(NSString *)deviceId + nextBatch:(NSString *)nextBatch + success:(void (^)(MXDehydratedDeviceEventsResponse * _Nonnull dehydratedDeviceEventsResponse))success + failure:(void (^)(NSError * _Nonnull error))failure; #pragma mark - Crypto: e2e keys backup diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index f932a1a1ea..48e8f6ff2f 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -1816,43 +1816,43 @@ - (MXHTTPOperation *)addPushRule:(NSString*)ruleId { case MXPushRuleKindOverride: kindString = @"override"; - if (conditions.count && actions.count) + if (conditions.count && actions) { content = @{@"conditions": conditions, @"actions": actions}; } - else if (actions.count) + else if (actions) { content = @{@"actions": actions}; } break; case MXPushRuleKindContent: kindString = @"content"; - if (pattern.length && actions.count) + if (pattern.length && actions) { content = @{@"pattern": pattern, @"actions": actions}; } break; case MXPushRuleKindRoom: kindString = @"room"; - if (actions.count) + if (actions) { content = @{@"actions": actions}; } break; case MXPushRuleKindSender: kindString = @"sender"; - if (actions.count) + if (actions) { content = @{@"actions": actions}; } break; case MXPushRuleKindUnderride: kindString = @"underride"; - if (conditions.count && actions.count) + if (conditions.count && actions) { content = @{@"conditions": conditions, @"actions": actions}; } - else if (actions.count) + else if (actions) { content = @{@"actions": actions}; } @@ -3077,7 +3077,7 @@ - (MXHTTPOperation*)redactEvent:(NSString*)eventId if (relations && [relations count] > 0) { - NSString* property = withRelationsIsStable ? @"with_relations" : @"org.matrix.msc3912.with_relations"; + NSString* property = withRelationsIsStable ? @"with_rel_types" : @"org.matrix.msc3912.with_relations"; parameters[property] = relations; } @@ -4947,78 +4947,93 @@ - (MXHTTPOperation *)keyChangesFrom:(NSString *)fromToken to:(NSString *)toToken }]; } +#pragma mark - Device dehydration -#pragma mark - Crypto: Dehydration +- (MXHTTPOperation*)createDehydratedDevice:(MXDehydratedDeviceCreationParameters *)parameters + success:(void (^)(NSString *deviceId))success + failure:(void (^)(NSError *error))failure +{ + MXWeakify(self); + return [httpClient requestWithMethod:@"PUT" + path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc3814.v1/dehydrated_device", credentials.homeServer, kMXAPIPrefixPathUnstable] + parameters:parameters.JSONDictionary + success:^(NSDictionary *JSONResponse) { + __block NSString *deviceId; + [self dispatchProcessing:^{ + MXJSONModelSetString(deviceId, JSONResponse[@"device_id"]) + } andCompletion:^{ + success(deviceId); + }]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; +} -- (MXHTTPOperation*)getDehydratedDeviceWithSuccess:(void (^)(MXDehydratedDevice *device))success - failure:(void (^)(NSError *error))failure +- (MXHTTPOperation*)retrieveDehydratedDeviceWithSuccess:(void (^)(MXDehydratedDeviceResponse *dehydratedDevice))success + failure:(void (^)(NSError *error))failure { MXWeakify(self); return [httpClient requestWithMethod:@"GET" - path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc2697.v2/dehydrated_device", credentials.homeServer, kMXAPIPrefixPathUnstable] + path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc3814.v1/dehydrated_device", credentials.homeServer, kMXAPIPrefixPathUnstable] parameters:@{} success:^(NSDictionary *JSONResponse) { - __block MXDehydratedDevice *device; - [self dispatchProcessing:^{ - MXJSONModelSetMXJSONModel(device, MXDehydratedDevice, JSONResponse); - } andCompletion:^{ - success(device); - }]; - } - failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self dispatchFailure:error inBlock:failure]; - }]; + __block MXDehydratedDeviceResponse *dehydratedDevice; + [self dispatchProcessing:^{ + MXJSONModelSetMXJSONModel(dehydratedDevice, MXDehydratedDeviceResponse, JSONResponse); + } andCompletion:^{ + success(dehydratedDevice); + }]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; } -- (MXHTTPOperation*)setDehydratedDevice:(MXDehydratedDevice *)device - withDisplayName:(NSString *)deviceDisplayName - success:(void (^)(NSString *deviceId))success - failure:(void (^)(NSError *error))failure +- (MXHTTPOperation*)deleteDehydratedDeviceWithSuccess:(void (^)(void))success + failure:(void (^)(NSError *error))failure { MXWeakify(self); - return [httpClient requestWithMethod:@"PUT" - path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc2697.v2/dehydrated_device", credentials.homeServer, kMXAPIPrefixPathUnstable] - parameters:@{ - @"initial_device_display_name": deviceDisplayName, - @"device_data": device.JSONDictionary} + return [httpClient requestWithMethod:@"DELETE" + path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc3814.v1/dehydrated_device", credentials.homeServer, kMXAPIPrefixPathUnstable] + parameters:nil success:^(NSDictionary *JSONResponse) { - __block NSString *deviceId; - [self dispatchProcessing:^{ - deviceId = JSONResponse[@"device_id"]; - } andCompletion:^{ - success(deviceId); - }]; - } - failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self dispatchFailure:error inBlock:failure]; - }]; + success(); + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; } -- (MXHTTPOperation*)claimDehydratedDeviceWithId:(NSString*)deviceId - Success:(void (^)(BOOL success))success - failure:(void (^)(NSError *error))failure +- (MXHTTPOperation*)retrieveDehydratedDeviceEventsForDeviceId:(NSString *)deviceId + nextBatch:(NSString *)nextBatch + success:(void (^)(MXDehydratedDeviceEventsResponse *dehydratedDeviceEventsResponse))success + failure:(void (^)(NSError *error))failure { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + if (nextBatch != nil) { + parameters[@"next_batch"] = nextBatch; + } + MXWeakify(self); return [httpClient requestWithMethod:@"POST" - path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc2697.v2/dehydrated_device/claim", credentials.homeServer, kMXAPIPrefixPathUnstable] - parameters:@{@"device_id": deviceId} + path:[NSString stringWithFormat:@"%@/%@/org.matrix.msc3814.v1/dehydrated_device/%@/events", credentials.homeServer, kMXAPIPrefixPathUnstable, [MXTools encodeURIComponent:deviceId]] + parameters:parameters success:^(NSDictionary *JSONResponse) { - __block BOOL successValue; - [self dispatchProcessing:^{ - successValue = [JSONResponse[@"success"] boolValue]; - } andCompletion:^{ - success(successValue); - }]; - } - failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self dispatchFailure:error inBlock:failure]; - }]; + __block MXDehydratedDeviceEventsResponse *dehydratedDeviceEventsResponse; + [self dispatchProcessing:^{ + MXJSONModelSetMXJSONModel(dehydratedDeviceEventsResponse, MXDehydratedDeviceEventsResponse, JSONResponse); + } andCompletion:^{ + success(dehydratedDeviceEventsResponse); + }]; + + + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; } - #pragma mark - Crypto: e2e keys backup - (MXHTTPOperation*)createKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion success:(void (^)(NSString *version))success diff --git a/MatrixSDK/MXSDKOptions.h b/MatrixSDK/MXSDKOptions.h index 89095ce26e..e5fe937bec 100644 --- a/MatrixSDK/MXSDKOptions.h +++ b/MatrixSDK/MXSDKOptions.h @@ -45,7 +45,7 @@ typedef NS_ENUM(NSUInteger, MXCallTransferType) NS_ASSUME_NONNULL_BEGIN -@protocol MXBackgroundModeHandler, MXCryptoV2Feature; +@protocol MXBackgroundModeHandler, MXCryptoV2MigrationDelegate; /** SDK options that can be set at the launch time. @@ -187,23 +187,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL enableRoomSharedHistoryOnInvite; /** - An object which controls the availabilty of the rust-based `MatrixCryptoSDK`. + The delegate for migrating account data from legacy crypto to rust-based Crypto SDK - @remark nil by default. + By default, nil. */ -@property (nonatomic, nullable) id cryptoSDKFeature; - -/** - Use the rust-based `MatrixCryptoSDK` instead of `MatrixSDK`'s internal crypto module. - - @remark this property is a convenience getter for `cryptoSDKFeature.isEnabled` - */ -@property (nonatomic, readonly) BOOL enableCryptoSDK; - -/** - The text-based identifier for the crypto module being used (e.g. native vs rust) - */ -@property (nonatomic, readonly) NSString *cryptoModuleId; +@property (nonatomic, nullable, weak) id cryptoMigrationDelegate; /** Enable symmetric room key backups @@ -225,14 +213,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic) BOOL enableSpaceGraph; -/** - Enable the calculating and display of progress during session startup, incl store migration, - syncing and response processing. - - @remark YES by default - */ -@property (nonatomic) BOOL enableStartupProgress; - @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/MXSDKOptions.m b/MatrixSDK/MXSDKOptions.m index 097b974ea8..66fde00341 100644 --- a/MatrixSDK/MXSDKOptions.m +++ b/MatrixSDK/MXSDKOptions.m @@ -54,28 +54,12 @@ - (instancetype)init _enableRoomSharedHistoryOnInvite = NO; _enableSymmetricBackup = NO; _enableNewClientInformationFeature = NO; - _enableStartupProgress = YES; - _enableSpaceGraph = YES; + _cryptoMigrationDelegate = nil; } return self; } -- (BOOL)enableCryptoSDK -{ - if (!self.cryptoSDKFeature) - { - MXLogError(@"[MXSDKOptions] enableCryptoSDK: Crypto SDK feature is not configured"); - return NO; - } - return self.cryptoSDKFeature.isEnabled; -} - -- (NSString *)cryptoModuleId -{ - return self.enableCryptoSDK ? @"rust" : @"native"; -} - - (void)setRoomListDataManagerClass:(Class)roomListDataManagerClass { // Sanity check diff --git a/MatrixSDK/MXSession.h b/MatrixSDK/MXSession.h index a9ce329a02..bfcb723119 100644 --- a/MatrixSDK/MXSession.h +++ b/MatrixSDK/MXSession.h @@ -1596,14 +1596,6 @@ typedef void (^MXOnBackgroundSyncFail)(NSError *error); inTimeline:(NSString*)timeline onComplete:(void (^)(NSArray *failedEvents))onComplete; -/** - Reset replay attack data for the given timeline. - - @param timeline the id of the timeline. - */ -- (void)resetReplayAttackCheckInTimeline:(NSString*)timeline; - - #pragma mark - Global events listeners /** Register a global listener to events related to the current session. diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index b251bc2df7..d5fe99096c 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -316,10 +316,7 @@ - (id)initWithMatrixRestClient:(MXRestClient*)mxRestClient _homeserverCapabilitiesService = [[MXHomeserverCapabilitiesService alloc] initWithSession: self]; [_homeserverCapabilitiesService updateWithCompletion:nil]; - if (MXSDKOptions.sharedInstance.enableStartupProgress) - { - _startupProgress = [[MXSessionStartupProgress alloc] init]; - } + _startupProgress = [[MXSessionStartupProgress alloc] init]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDidDecryptEvent:) name:kMXEventDidDecryptNotification object:nil]; @@ -401,24 +398,12 @@ -(void)setStore:(id)store success:(void (^)(void))onStoreDataReady fail // Check if the user has enabled crypto MXWeakify(self); - [MXLegacyCrypto initializeCryptoWithMatrixSession:self migrationProgress:^(double progress) { - if (MXSDKOptions.sharedInstance.enableStartupProgress) - { - [self.startupProgress updateProgressForStage:MXSessionStartupStageStoreMigration progress:progress]; - } + [self initializeCryptoWithProgress:^(double progress) { + [self.startupProgress updateProgressForStage:MXSessionStartupStageStoreMigration progress:progress]; - } complete:^(id crypto, NSError *error) { + } success:^(id crypto) { MXStrongifyAndReturnIfNil(self); - if (!crypto && error) - { - if (failure) - { - failure(error); - } - return; - } - self->_crypto = crypto; // Sanity check: The session may be closed before the end of this operation. @@ -537,6 +522,11 @@ -(void)setStore:(id)store success:(void (^)(void))onStoreDataReady fail // The SDK client can use this data onStoreDataReady(); } + } failure:^(NSError *error) { + if (failure) + { + failure(error); + } }]; } failure:^(NSError *error) { @@ -549,6 +539,34 @@ -(void)setStore:(id)store success:(void (^)(void))onStoreDataReady fail }]; } +- (void)initializeCryptoWithProgress:(void (^)(double))progress + success:(void (^)(id crypto))success + failure:(void (^)(NSError *error))failure +{ + BOOL enableCrypto = [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession || [MXCryptoV2Factory.shared hasCryptoDataFor:self]; + if (!enableCrypto) + { + MXLogWarning(@"[MXSession] initializeCrypto: Not starting crypto automatically due to SDK settings"); + dispatch_async(dispatch_get_main_queue(), ^{ + success(nil); + }); + return; + } + + [MXCryptoV2Factory.shared buildCryptoWithSession:self + migrationProgress:progress + success:^(id crypto) { + + MXLogDebug(@"[MXSession] initializeCrypto: Successfully initialized crypto module"); + success(crypto); + + } failure:^(NSError *error) { + + MXLogErrorDetails(@"[MXSession] initializeCrypto: Error initialized crypto module", error); + failure(error); + }]; +} + - (void)setRoomListDataManager:(id)roomListDataManager { NSParameterAssert(_roomListDataManager == nil); @@ -572,7 +590,7 @@ - (void)handleSyncResponse:(MXSyncResponse *)syncResponse // Check whether this is the initial sync BOOL isInitialSync = !self.isEventStreamInitialised; - [self handleCryptoSyncResponse:syncResponse onComplete:^{ + [self handleCryptoEventsInSyncResponse:syncResponse onComplete:^{ dispatch_group_t dispatchGroup = dispatch_group_create(); @@ -589,7 +607,7 @@ - (void)handleSyncResponse:(MXSyncResponse *)syncResponse void(^dispatch_group_leave_with_progress)(dispatch_group_t) = ^(dispatch_group_t dispatchGroup) { dispatch_group_leave(dispatchGroup); - if (MXSDKOptions.sharedInstance.enableStartupProgress && progress) + if (progress) { progress([self.startupProgress overallProgressForStep:completedRooms totalCount:totalRooms progress:1]); completedRooms += 1; @@ -776,30 +794,6 @@ - (void)handleSyncResponse:(MXSyncResponse *)syncResponse // Sync point: wait that all rooms in the /sync response have been loaded // and their /sync response has been processed dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ - - // Legacy crypto requires that we deal with device list changes, OTKs etc at the end of the sync loop. - // This will be removed altogether with `MXLegacyCrypto` - if ([self.crypto isKindOfClass:[MXLegacyCrypto class]]) - { - // Handle device list updates - if (syncResponse.deviceLists) - { - [(MXLegacyCrypto *)self.crypto handleDeviceListsChanges:syncResponse.deviceLists]; - } - - // Handle one_time_keys_count - if (syncResponse.deviceOneTimeKeysCount) - { - [(MXLegacyCrypto *)self.crypto handleDeviceOneTimeKeysCount:syncResponse.deviceOneTimeKeysCount]; - } - - [(MXLegacyCrypto *)self.crypto handleDeviceUnusedFallbackKeys:syncResponse.unusedFallbackKeys]; - - // Tell the crypto module to do its processing - [(MXLegacyCrypto *)self.crypto onSyncCompleted:self.store.eventStreamToken - nextSyncToken:syncResponse.nextBatch - catchingUp:self.catchingUp]; - } // Update live event stream token MXLogDebug(@"[MXSession] Next sync token: %@", syncResponse.nextBatch); @@ -1456,7 +1450,7 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout setPresence:(NSString*)setPresence { // We only want to report sync progress when doing initial sync - BOOL shoulReportStartupProgress = MXSDKOptions.sharedInstance.enableStartupProgress && !self.isEventStreamInitialised; + BOOL shoulReportStartupProgress = !self.isEventStreamInitialised; if (shoulReportStartupProgress) { // There is no way to track percentage progress when syncing with the server, so we always use 0% @@ -1979,7 +1973,6 @@ - (void)handleAccountData:(NSDictionary*)accountDataUpdate } } - [self validateAccountData]; self.store.userAccountData = _accountData.accountData; // Trigger a global notification for the account data update @@ -1992,27 +1985,6 @@ - (void)handleAccountData:(NSDictionary*)accountDataUpdate } } -/** - Private method to validate local account data and report any potential state corruption - */ -- (void)validateAccountData -{ - if (![self.crypto isKindOfClass:[MXLegacyCrypto class]]) - { - return; - } - - // Detecting an issue in legacy crypto where more than one valid SSSS key is present on the client - // https://github.com/vector-im/element-ios/issues/4569 - NSInteger keysCount = ((MXLegacyCrypto *)self.crypto).secretStorage.numberOfValidKeys; - if (keysCount > 1) - { - MXLogErrorDetails(@"[MXSession] validateAccountData: Detected multiple valid SSSS keys, should only have one at most", @{ - @"count": @(keysCount) - }); - } -} - - (void)updateSummaryDirectUserIdForRooms:(NSSet *)roomIds { // If the initial sync response is not processed enough, rooms is not yet mounted. @@ -2037,95 +2009,15 @@ - (void)updateSummaryDirectUserIdForRooms:(NSSet *)roomIds } } -// Temporary junction to deal with sync response depending on the variant of crypto -// that cannot be easily hidden behind a protocol. Legacy implementation will eventually -// be fully removed. -- (void)handleCryptoSyncResponse:(MXSyncResponse *)syncResponse - onComplete:(void (^)(void))onComplete -{ - if (!self.crypto || [self.crypto isKindOfClass:[MXLegacyCrypto class]]) - { - // Legacy crypto requires pre-processed to-device events before everything else to make future decryptions work - [self handleToDeviceEvents:syncResponse.toDevice.events onComplete:onComplete]; - } - else - { - // New and all future crypto modules can handle the entire sync response in full - [self.crypto handleSyncResponse:syncResponse onComplete:onComplete]; - } -} - -- (void)handleToDeviceEvents:(NSArray *)events onComplete:(void (^)(void))onComplete +- (void)handleCryptoEventsInSyncResponse:(MXSyncResponse *)syncResponse onComplete:(void (^)(void))onComplete { - NSMutableArray *supportedEvents = [NSMutableArray arrayWithCapacity:events.count]; - for (MXEvent *event in events) - { - if ([MXTools isSupportedToDeviceEvent:event]) - { - MXLogDebug(@"[MXSession] handleToDeviceEvents: Processing new to-device event msgid: %@", event.content[kMXToDeviceMessageId]) - [supportedEvents addObject:event]; - } - } - - if (supportedEvents.count == 0) + if (!self.crypto) { onComplete(); return; } - [self decryptEvents:supportedEvents inTimeline:nil onComplete:^(NSArray *failedEvents) { - dispatch_group_t dispatchGroup = dispatch_group_create(); - - for (MXEvent *event in supportedEvents) - { - if (!event.decryptionError) - { - MXLogDebug(@"[MXSession] handleToDeviceEvents: Received new to-device event `%@` from `%@` msgid: %@", event.type, event.sender, event.wireContent[kMXToDeviceMessageId]) - dispatch_group_enter(dispatchGroup); - [self handleToDeviceEvent:event onComplete:^{ - dispatch_group_leave(dispatchGroup); - }]; - } - else - { - MXLogDebug(@"[MXSession] handleToDeviceEvents: Warning: Unable to decrypt to-device event: %@\nError: %@", event.wireContent[kMXMessageBodyKey], event.decryptionError); - } - } - - dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ - onComplete(); - }); - }]; -} - -- (void)handleToDeviceEvent:(MXEvent *)event onComplete:(void (^)(void))onComplete -{ - void (^onHandleToDeviceEventDone)(void) = ^(void) { - [[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionOnToDeviceEventNotification - object:self - userInfo:@{ - kMXSessionNotificationEventKey: event - }]; - - onComplete(); - }; - - switch (event.eventType) - { - case MXEventTypeRoomKey: - { - if ([_crypto isKindOfClass:[MXLegacyCrypto class]]) - { - [(MXLegacyCrypto *)_crypto handleRoomKeyEvent:event onComplete:onHandleToDeviceEventDone]; - } - break; - } - - default: - onHandleToDeviceEventDone(); - break; - } - [_eventStreamService dispatchOnLiveToDeviceWithEvent:event]; + [self.crypto handleSyncResponse:syncResponse onComplete:onComplete]; } /** @@ -2206,17 +2098,10 @@ - (void)handleBackgroundSyncCacheIfRequiredWithCompletion:(void (^)(void))comple [asyncTaskQueue asyncWithExecute:^(void (^ taskCompleted)(void)) { [syncResponseStoreManager mergedSyncResponseFromSyncResponseIds:outdatedSyncResponseIds completion:^(MXCachedSyncResponse * _Nullable outdatedCachedSyncResponse) { - if (outdatedCachedSyncResponse) - { - [self handleOutdatedSyncResponse:outdatedCachedSyncResponse.syncResponse - completion:^{ - taskCompleted(); - }]; - } - else - { + // There is no need to handle `outdatedCachedSyncResponse` manually anymore, ignoring the result + dispatch_async(dispatch_get_main_queue(), ^{ taskCompleted(); - } + }); }]; }]; @@ -2265,26 +2150,6 @@ - (void)handleBackgroundSyncCacheIfRequiredWithCompletion:(void (^)(void))comple }]; } -- (void)handleOutdatedSyncResponse:(MXSyncResponse *)syncResponse - completion:(void (^)(void))completion -{ - MXLogDebug(@"[MXSession] handleOutdatedSyncResponse: %tu joined rooms, %tu invited rooms, %tu left rooms, %tu toDevice events.", syncResponse.rooms.join.count, syncResponse.rooms.invite.count, syncResponse.rooms.leave.count, syncResponse.toDevice.events.count); - - if (!self.crypto || [self.crypto isKindOfClass:[MXLegacyCrypto class]]) - { - // Legacy crypto requires pre-processed to-device events before everything else to make future decryptions work - [self handleToDeviceEvents:syncResponse.toDevice.events onComplete:completion]; - } - else - { - // Only legacy crypto requires different DBs for foreground and background processes, other crypto modules - // write to a single DB in both processes, so there is no need to replay outdated sync response - dispatch_async(dispatch_get_main_queue(), ^{ - completion(); - }); - } -} - #pragma mark - Options - (void)enableVoIPWithCallStack:(id)callStack { @@ -2300,32 +2165,38 @@ - (void)enableCrypto:(BOOL)enableCrypto success:(void (^)(void))success failure: if (enableCrypto && !_crypto) { - NSError *error; - _crypto = [MXLegacyCrypto createCryptoWithMatrixSession:self error:&error]; - if (!_crypto && error) - { - if (failure) + MXWeakify(self); + [MXCryptoV2Factory.shared buildCryptoWithSession:self + migrationProgress:nil + success:^(id crypto) { + + MXLogDebug(@"[MXSession] enableCrypto: Successfully initialized crypto module"); + MXStrongifyAndReturnIfNil(self); + self->_crypto = crypto; + + if (self->_state == MXSessionStateRunning) { - failure(error); + [self startCrypto:success failure:failure]; } - return; - } - - if (_state == MXSessionStateRunning) - { - [self startCrypto:success failure:failure]; - } - else - { - MXLogDebug(@"[MXSesion] enableCrypto: crypto module will be start later (MXSession.state: %@)", [MXTools readableSessionState:_state]); + else + { + MXLogDebug(@"[MXSesion] enableCrypto: crypto module will be start later (MXSession.state: %@)", [MXTools readableSessionState:self->_state]); - if (success) + if (success) + { + dispatch_async(dispatch_get_main_queue(), ^{ + success(); + }); + } + } + + } failure:^(NSError *error) { + MXLogErrorDetails(@"[MXSession] enableCrypto: Error initialized crypto module", error); + if (failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - success(); - }); + failure(error); } - } + }]; } else if (!enableCrypto && _crypto) { @@ -3174,6 +3045,8 @@ - (void)removeRoom:(NSString *)roomId // And remove the room and its summary from the list [rooms removeObjectForKey:roomId]; [roomSummaries removeObjectForKey:roomId]; + // Remove room from breadcrub list + [self removeBreadcrumbWithRoomWithId:roomId success:nil failure:nil]; // Broadcast the left room [[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionDidLeaveRoomNotification @@ -3390,7 +3263,7 @@ - (void)fixRoomsSummariesLastMessageWithMaxServerPaginationCount:(NSUInteger)max __block NSInteger completedRooms = 0; void(^dispatch_group_leave_with_progress)(dispatch_group_t) = ^(dispatch_group_t dispatchGroup) { dispatch_group_leave(dispatchGroup); - if (MXSDKOptions.sharedInstance.enableStartupProgress && progress) + if (progress) { progress([self.startupProgress overallProgressForStep:completedRooms totalCount:self.rooms.count progress:1]); completedRooms += 1; @@ -4733,6 +4606,43 @@ - (void)updateBreadcrumbsWithRoomWithId:(NSString *)roomId }]; } +// Update breadcrub list when leaving a room +- (void)removeBreadcrumbWithRoomWithId:(NSString *)roomId + success:(void (^)(void))success + failure:(void (^)(NSError *error))failure +{ + NSDictionary *breadcrumbs = [self.accountData accountDataForEventType:kMXAccountDataTypeBreadcrumbs]; + + NSMutableArray *recentRoomIds = breadcrumbs[kMXAccountDataTypeRecentRoomsKey] ? [NSMutableArray arrayWithArray:breadcrumbs[kMXAccountDataTypeRecentRoomsKey]] : [NSMutableArray array]; + + NSInteger index = [recentRoomIds indexOfObject:roomId]; + if (index != NSNotFound) + { + [recentRoomIds removeObjectAtIndex:index]; + + [self setAccountData:@{kMXAccountDataTypeRecentRoomsKey : recentRoomIds} + forType:kMXAccountDataTypeBreadcrumbs + success:^{ + if (success) + { + success(); + } + } failure:^(NSError *error) { + if (failure) + { + failure(error); + } + }]; + } + else + { + if (success) + { + success(); + } + } +} + #pragma mark - Homeserver information - (MXWellKnown *)homeserverWellknown { @@ -5031,14 +4941,6 @@ - (void)decryptEvents:(NSArray *)events } } -- (void)resetReplayAttackCheckInTimeline:(NSString*)timeline -{ - if ([_crypto isKindOfClass:[MXLegacyCrypto class]]) - { - [(MXLegacyCrypto *)_crypto resetReplayAttackCheckInTimeline:timeline]; - } -} - // Called when an event finally got decrypted after a late room key reception - (void)onDidDecryptEvent:(NSNotification *)notification { diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index 0da04567ad..84dd77bcc5 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -194,7 +194,6 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXGroupsSyncResponse.h" #import "MXInvitedGroupSync.h" #import "MXGroupSyncProfile.h" -#import "MXDehydrationService.h" #import "MXEventAssetType.h" #import "MXDevice.h" diff --git a/MatrixSDK/MatrixSDKVersion.m b/MatrixSDK/MatrixSDKVersion.m index b65d29446d..3f16e20dca 100644 --- a/MatrixSDK/MatrixSDKVersion.m +++ b/MatrixSDK/MatrixSDKVersion.m @@ -16,4 +16,4 @@ #import -NSString *const MatrixSDKVersion = @"0.26.9"; +NSString *const MatrixSDKVersion = @"0.27.6"; diff --git a/MatrixSDK/NotificationCenter/MXNotificationCenter.m b/MatrixSDK/NotificationCenter/MXNotificationCenter.m index 1e80429ea7..d449ed0325 100644 --- a/MatrixSDK/NotificationCenter/MXNotificationCenter.m +++ b/MatrixSDK/NotificationCenter/MXNotificationCenter.m @@ -207,6 +207,7 @@ - (MXPushRule *)ruleMatchingEvent:(MXEvent *)event roomState:(MXRoomState*)roomS { MXLogDebug(@"[MXNotificationCenter] Warning: There is no MXPushRuleConditionChecker to check condition of kind: %@", condition.kind); conditionsOk = NO; + break; // Don't go further as we cannot guarantee that this rule matches } } break; @@ -579,6 +580,7 @@ - (NSArray*)encodeActionsWithNotify:(BOOL)notify highlight:(BOOL)highlight { NSMutableArray *actions = [NSMutableArray array]; + // Support for MSC3987: The dont_notify push rule action is deprecated and replaced by an empty actions list. if (notify) { [actions addObject:@"notify"]; @@ -597,10 +599,6 @@ - (NSArray*)encodeActionsWithNotify:(BOOL)notify [actions addObject:@{@"set_tweak": @"highlight", @"value": @NO}]; } } - else - { - [actions addObject:@"dont_notify"]; - } return actions; } @@ -615,7 +613,8 @@ - (void)shouldNotify:(MXEvent*)event roomState:(MXRoomState*)roomState if (rule) { // Make sure this is not a rule to prevent from generating a notification - BOOL actionNotify = YES; + // Support for MSC3987: The dont_notify push rule action is deprecated and replaced by an empty actions list. + BOOL actionNotify = (rule.actions.count > 0); if (1 == rule.actions.count) { MXPushRuleAction *action = rule.actions[0]; diff --git a/MatrixSDK/Room/Polls/PollAggregator.swift b/MatrixSDK/Room/Polls/PollAggregator.swift index 85dadc1a74..63ded7ae1d 100644 --- a/MatrixSDK/Room/Polls/PollAggregator.swift +++ b/MatrixSDK/Room/Polls/PollAggregator.swift @@ -54,7 +54,7 @@ public class PollAggregator { private var events: [MXEvent] = [] private var hasBeenEdited = false - public private(set) var poll: PollProtocol! { + public private(set) var poll: PollProtocol? { didSet { delegate?.pollAggregatorDidUpdateData(self) } @@ -88,10 +88,10 @@ public class PollAggregator { throw PollAggregatorError.invalidPollStartEvent } - try self.init(session: session, room: room, pollStartEventId: pollStartEventId, delegate: delegate) + self.init(session: session, room: room, pollStartEventId: pollStartEventId, delegate: delegate) } - public init(session: MXSession, room: MXRoom, pollStartEventId: String, delegate: PollAggregatorDelegate? = nil) throws { + public init(session: MXSession, room: MXRoom, pollStartEventId: String, delegate: PollAggregatorDelegate? = nil) { self.session = session self.room = room self.pollStartEventId = pollStartEventId @@ -100,7 +100,9 @@ public class PollAggregator { NotificationCenter.default.addObserver(self, selector: #selector(handleRoomDataFlush), name: .mxRoomDidFlushData, object: self.room) setupEditListener() - try buildPollStartContent() + buildPollStartContent() + + reloadPollData() } private func setupEditListener() { @@ -111,34 +113,35 @@ public class PollAggregator { return } - do { - try self.buildPollStartContent() - } catch { - self.delegate?.pollAggregator(self, didFailWithError: PollAggregatorError.invalidPollStartEvent) - } + self.buildPollStartContent() } } - private func buildPollStartContent() throws { - guard let event = session.store.event(withEventId: pollStartEventId, inRoom: room.roomId), - let eventContent = MXEventContentPollStart(fromJSON: event.content), - eventContent.answerOptions.count >= Constants.minAnswerOptionCount + private func buildPollStartContent() { + let event = session.store.event(withEventId: pollStartEventId, inRoom: room.roomId) + tryUpdatePollStartedEvent(with: event) + if let pollStartedEvent = pollStartedEvent { + poll = pollBuilder.build(pollStartEventContent: pollStartEventContent, + pollStartEvent: pollStartedEvent, + events: events, + currentUserIdentifier: session.myUserId, + hasBeenEdited: hasBeenEdited) + } + } + + private func tryUpdatePollStartedEvent(with event: MXEvent?) { + guard + let event = event, + let eventContent = MXEventContentPollStart(fromJSON: event.content), + eventContent.answerOptions.count >= Constants.minAnswerOptionCount else { - throw PollAggregatorError.invalidPollStartEvent + delegate?.pollAggregator(self, didFailWithError: PollAggregatorError.invalidPollStartEvent) + return } pollStartedEvent = event pollStartEventContent = eventContent - hasBeenEdited = (event.unsignedData.relations?.replace != nil) - - poll = pollBuilder.build(pollStartEventContent: eventContent, - pollStartEvent: pollStartedEvent, - events: events, - currentUserIdentifier: session.myUserId, - hasBeenEdited: hasBeenEdited) - - reloadPollData() } @objc private func handleRoomDataFlush(sender: Notification) { @@ -157,8 +160,12 @@ public class PollAggregator { return } - self.events.removeAll() + self.tryUpdatePollStartedEvent(with: response.originalEvent) + if self.pollStartedEvent == nil { + return + } + self.events.removeAll() self.events.append(contentsOf: response.chunk) let eventTypes = [kMXEventTypeStringPollResponse, kMXEventTypeStringPollResponseMSC3381, kMXEventTypeStringPollEnd, kMXEventTypeStringPollEndMSC3381] @@ -179,7 +186,7 @@ public class PollAggregator { currentUserIdentifier: self.session.myUserId, hasBeenEdited: self.hasBeenEdited) } as Any - + self.poll = self.pollBuilder.build(pollStartEventContent: self.pollStartEventContent, pollStartEvent: self.pollStartedEvent, events: self.events, diff --git a/MatrixSDK/Space/MXSpace.swift b/MatrixSDK/Space/MXSpace.swift index 6c1533c436..c60312cde9 100644 --- a/MatrixSDK/Space/MXSpace.swift +++ b/MatrixSDK/Space/MXSpace.swift @@ -346,7 +346,11 @@ public class MXSpace: NSObject { /// /// - Returns: the mimnimum power level required to add a room to this space public func minimumPowerLevelForAddingRoom(with powerLevels: MXRoomPowerLevels) -> Int { - return powerLevels.events["m.space.child"] as? Int ?? powerLevels.stateDefault + guard let events = powerLevels.events else { + return powerLevels.stateDefault + } + + return events["m.space.child"] as? Int ?? powerLevels.stateDefault } // MARK: - Private diff --git a/MatrixSDK/Space/MXSpaceNotificationCounter.swift b/MatrixSDK/Space/MXSpaceNotificationCounter.swift index a27e1bbcd0..953b67755b 100644 --- a/MatrixSDK/Space/MXSpaceNotificationCounter.swift +++ b/MatrixSDK/Space/MXSpaceNotificationCounter.swift @@ -225,6 +225,12 @@ public class MXSpaceNotificationCounter: NSObject { continue } + // Support for MSC3987: The dont_notify push rule action is deprecated. + if rule.actions.isEmpty { + return rule.enabled + } + + // Compatibility support. for ruleAction in ruleActions where ruleAction.actionType == MXPushRuleActionTypeDontNotify { return rule.enabled } diff --git a/MatrixSDK/Utils/MXTools.m b/MatrixSDK/Utils/MXTools.m index e17e7134cb..22435cd7dc 100644 --- a/MatrixSDK/Utils/MXTools.m +++ b/MatrixSDK/Utils/MXTools.m @@ -30,7 +30,7 @@ #warning File has not been annotated with nullability, see MX_ASSUME_MISSING_NULLABILITY_BEGIN #pragma mark - Constant definition -NSString *const kMXToolsRegexStringForEmailAddress = @"[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}"; +NSString *const kMXToolsRegexStringForEmailAddress = @"^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$"; // The HS domain part in Matrix identifiers #define MATRIX_HOMESERVER_DOMAIN_REGEX @"[A-Z0-9]+((\\.|\\-)[A-Z0-9]+){0,}(:[0-9]{2,5})?" diff --git a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift index 7f01767846..2f1e386e2e 100644 --- a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift +++ b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift @@ -37,8 +37,8 @@ class MXCrossSigningInfoUnitTests: XCTestCase { userId: "Alice", trustsOurOwnDevice: false, masterKey: masterKeys.jsonString(), - selfSigningKey: selfSigningKeys.jsonString(), - userSigningKey: userSigningKeys.jsonString() + userSigningKey: userSigningKeys.jsonString(), + selfSigningKey: selfSigningKeys.jsonString() ) let userIdentity = MXCryptoUserIdentityWrapper( identity: identity, diff --git a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift index 4ed6168f50..c01a7d2a0f 100644 --- a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift +++ b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift @@ -39,8 +39,8 @@ class MXCrossSigningInfoSourceUnitTests: XCTestCase { userId: "Alice", trustsOurOwnDevice: true, masterKey: "master", - selfSigningKey: "self", - userSigningKey: "user" + userSigningKey: "user", + selfSigningKey: "self" ) ] cryptoSource.verification = [ diff --git a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift index 2de42cdb8c..d1935e7ae9 100644 --- a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift @@ -101,8 +101,8 @@ class MXCrossSigningV2UnitTests: XCTestCase { userId: "Alice", trustsOurOwnDevice: true, masterKey: "", - selfSigningKey: "", - userSigningKey: "" + userSigningKey: "", + selfSigningKey: "" ) ] crossSigning.refreshState { _ in @@ -120,8 +120,8 @@ class MXCrossSigningV2UnitTests: XCTestCase { userId: "Alice", trustsOurOwnDevice: true, masterKey: "", - selfSigningKey: "", - userSigningKey: "" + userSigningKey: "", + selfSigningKey: "" ) ] crossSigning.refreshState { _ in @@ -149,8 +149,8 @@ class MXCrossSigningV2UnitTests: XCTestCase { userId: "Alice", trustsOurOwnDevice: true, masterKey: "", - selfSigningKey: "", - userSigningKey: "" + userSigningKey: "", + selfSigningKey: "" ) ] @@ -217,3 +217,15 @@ private extension MXCrossSigningV2 { } } } + +private extension MXCrossSigning { + func refreshState() async throws { + return try await withCheckedThrowingContinuation { continuation in + refreshState { _ in + continuation.resume() + } failure: { error in + continuation.resume(throwing: error) + } + } + } +} diff --git a/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift b/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift index 2b5cb493ff..29ba42e3be 100644 --- a/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift @@ -40,7 +40,8 @@ extension Device { displayName: displayName, isBlocked: isBlocked, locallyTrusted: locallyTrusted, - crossSigningTrusted: crossSigningTrusted + crossSigningTrusted: crossSigningTrusted, + firstTimeSeenTs: 0 ) } } diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoMachineUnitTests.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoMachineUnitTests.swift index 0ef92ebcf3..9456290585 100644 --- a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoMachineUnitTests.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoMachineUnitTests.swift @@ -156,7 +156,8 @@ class MXCryptoMachineUnitTests: XCTestCase { toDevice: nil, deviceLists: nil, deviceOneTimeKeysCounts: [:], - unusedFallbackKeys: nil + unusedFallbackKeys: nil, + nextBatchToken: "" ) XCTAssertEqual(result.events.count, 0) } @@ -174,7 +175,8 @@ class MXCryptoMachineUnitTests: XCTestCase { toDevice: toDevice, deviceLists: deviceList, deviceOneTimeKeysCounts: [:], - unusedFallbackKeys: nil + unusedFallbackKeys: nil, + nextBatchToken: "" ) XCTAssertEqual(result.events.count, 1) } @@ -204,8 +206,8 @@ class MXCryptoMachineUnitTests: XCTestCase { XCTAssertEqual(request?.state(), .cancelled( cancelInfo: .init( - cancelCode: "m.user", reason: "The user cancelled the verification.", + cancelCode: "m.user", cancelledByUs: false ) )) diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift index 570e35d392..171d3b6bab 100644 --- a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift @@ -41,6 +41,10 @@ class DevicesSourceStub: CryptoIdentityStub, MXCryptoDevicesSource { func devices(userId: String) -> [Device] { return devices[userId]?.map { $0.value } ?? [] } + + func dehydratedDevices() -> DehydratedDevicesProtocol { + fatalError() + } } class UserIdentitySourceStub: CryptoIdentityStub, MXCryptoUserIdentitySource { @@ -138,7 +142,8 @@ class CryptoCrossSigningStub: CryptoIdentityStub, MXCryptoCrossSigning { isBlocked: device.isBlocked, locallyTrusted: device.locallyTrusted, // Modify cross signing trusted - crossSigningTrusted: true + crossSigningTrusted: true, + firstTimeSeenTs: 0 ) } @@ -154,6 +159,14 @@ class CryptoCrossSigningStub: CryptoIdentityStub, MXCryptoCrossSigning { func devices(userId: String) -> [Device] { return devices[userId]?.map { $0.value } ?? [] } + + func dehydratedDevices() -> DehydratedDevicesProtocol { + fatalError() + } + + func queryMissingSecretsFromOtherSessions() async throws { + + } } class CryptoVerificationStub: CryptoIdentityStub { diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXKeyProviderStub.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXKeyProviderStub.swift new file mode 100644 index 0000000000..73b7781fdd --- /dev/null +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXKeyProviderStub.swift @@ -0,0 +1,31 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +class MXKeyProviderStub: NSObject, MXKeyProviderDelegate { + func isEncryptionAvailableForData(ofType dataType: String) -> Bool { + return true + } + + func hasKeyForData(ofType dataType: String) -> Bool { + return true + } + + func keyDataForData(ofType dataType: String) -> MXKeyData? { + MXRawDataKey(key: "1234".data(using: .ascii)!) + } +} diff --git a/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift b/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift deleted file mode 100644 index 2e1867afc7..0000000000 --- a/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright 2023 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -class MXCryptoV2FactoryTests: XCTestCase { - class KeyProvider: NSObject, MXKeyProviderDelegate { - func isEncryptionAvailableForData(ofType dataType: String) -> Bool { - return true - } - - func hasKeyForData(ofType dataType: String) -> Bool { - return true - } - - func keyDataForData(ofType dataType: String) -> MXKeyData? { - MXRawDataKey(key: "1234".data(using: .ascii)!) - } - } - - var data: MatrixSDKTestsData! - var e2eData: MatrixSDKTestsE2EData! - var factory: MXCryptoV2Factory! - - override func setUp() { - data = .init() - e2eData = .init(matrixSDKTestsData: data) - factory = MXCryptoV2Factory() - MXKeyProvider.sharedInstance().delegate = KeyProvider() - } - - override func tearDown() { - MXKeyProvider.sharedInstance().delegate = nil - } - - private func buildCrypto(session: MXSession) async throws -> (MXCrypto?, Bool) { - try await withCheckedThrowingContinuation { cont in - var hasMigrated = false - factory.buildCrypto( - session: session) { _ in - hasMigrated = true - } success: { - cont.resume(returning: ($0, hasMigrated)) - } failure: { - cont.resume(throwing: $0) - } - } - } - - func test_doesNotMigrateNewUser() async throws { - let env = try await e2eData.startE2ETest() - let session = env.session - - // Simulating new user as one without a crypto database - MXRealmCryptoStore.delete(with: session.credentials) - - // Build crypto and assert no migration has been performed - let (crypto, hasMigrated) = try await buildCrypto(session: session) - XCTAssertNotNil(crypto) - XCTAssertFalse(hasMigrated) - - // Assert that we have not created any legacy store for this user - let legacyStore = MXRealmCryptoStore.init(credentials: session.credentials) - XCTAssertNil(legacyStore) - - await env.close() - } - - func test_fullyMigratesLegacyUser() async throws { - let env = try await e2eData.startE2ETest() - let session = env.session - var legacyStore = session.legacyCrypto?.store - - // Assert that we have a legacy store that has not yet been deprecated - XCTAssertNotNil(legacyStore) - XCTAssertEqual(legacyStore?.cryptoVersion, .version2) - - // Build crypto and assert migration has been performed - let (crypto, hasMigrated) = try await buildCrypto(session: session) - XCTAssertNotNil(crypto) - XCTAssertTrue(hasMigrated) - - // Assert that we no longer have a legacy store for this user - legacyStore = MXRealmCryptoStore(credentials: session.credentials) - XCTAssertNil(legacyStore) - - await env.close() - } - - func test_migratesPartiallyMigratedUser() async throws { - let env = try await e2eData.startE2ETest() - let session = env.session - - // We set the legacy store as partially deprecated - var legacyStore = session.legacyCrypto?.store - XCTAssertNotNil(legacyStore) - legacyStore?.cryptoVersion = .deprecated1 - - // Build crypto and assert migration has been performed - let (crypto, hasMigrated) = try await buildCrypto(session: session) - XCTAssertNotNil(crypto) - XCTAssertTrue(hasMigrated) - - // Assert that we no longer have a legacy store for this user - legacyStore = MXRealmCryptoStore(credentials: session.credentials) - XCTAssertNil(legacyStore) - - await env.close() - } - - func test_doesNotMigrateDeprecatedStore() async throws { - let env = try await e2eData.startE2ETest() - let session = env.session - - // We set the legacy store as fully deprecated - var legacyStore = session.legacyCrypto?.store - XCTAssertNotNil(legacyStore) - legacyStore?.cryptoVersion = .deprecated3 - - // Build crypto and assert no migration has been performed - let (crypto, hasMigrated) = try await buildCrypto(session: session) - XCTAssertNotNil(crypto) - XCTAssertFalse(hasMigrated) - - // Assert that we no longer have a legacy store for this user - legacyStore = MXRealmCryptoStore(credentials: session.credentials) - XCTAssertNil(legacyStore) - - await env.close() - } -} diff --git a/MatrixSDKTests/Crypto/MXCryptoV2FactoryUnitTests.swift b/MatrixSDKTests/Crypto/MXCryptoV2FactoryUnitTests.swift new file mode 100644 index 0000000000..fae681fca3 --- /dev/null +++ b/MatrixSDKTests/Crypto/MXCryptoV2FactoryUnitTests.swift @@ -0,0 +1,151 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +@testable import MatrixSDK + +class MXCryptoV2FactoryUnitTests: XCTestCase { + class MXSessionStub: MXSession { + var stubbedCredentials: MXCredentials! + override var credentials: MXCredentials! { + return stubbedCredentials + } + + override var myUserId: String! { + return stubbedCredentials.userId + } + + override var aggregations: MXAggregations! { + return MXAggregations() + } + + override var matrixRestClient: MXRestClient! { + return MXRestClientStub(credentials: credentials) + } + } + + var factory: MXCryptoV2Factory! + + override func setUp() async throws { + factory = MXCryptoV2Factory() + MXKeyProvider.sharedInstance().delegate = MXKeyProviderStub() + } + + override func tearDown() async throws { + try LegacyRealmStore.deleteAllStores() + MXKeyProvider.sharedInstance().delegate = nil + } + + private func makeSession(userId: String) -> MXSession { + let credentials = MXCredentials() + credentials.userId = userId + + let session = MXSessionStub() + session.stubbedCredentials = credentials + return session + } + + private func buildCrypto(account: LegacyRealmStore.Account) async throws -> (MXCrypto?, Bool) { + let session = MXSessionStub() + session.stubbedCredentials = account.credentials + + return try await withCheckedThrowingContinuation { cont in + var hasMigrated = false + factory.buildCrypto( + session: session) { _ in + hasMigrated = true + } success: { + cont.resume(returning: ($0, hasMigrated)) + } failure: { + cont.resume(throwing: $0) + } + } + } + + func test_hasCryptoData() throws { + let alice = "Alice" + let bob = "Bob" + + // Only create crypto data for alice + let aliceUrl = try MXCryptoMachineStore.storeURL(for: alice) + let data = "something".data(using: .ascii)! + try data.write(to: aliceUrl) + + let aliceSession = makeSession(userId: alice) + XCTAssertTrue(MXCryptoV2Factory.shared.hasCryptoData(for: aliceSession)) + + let bobSession = makeSession(userId: bob) + XCTAssertFalse(MXCryptoV2Factory.shared.hasCryptoData(for: bobSession)) + } + + func test_doesNotMigrateNewUser() async throws { + // Build crypto and assert no migration has been performed + let (crypto, hasMigrated) = try await buildCrypto(account: .version2) + XCTAssertNotNil(crypto) + XCTAssertFalse(hasMigrated) + } + + func test_fullyMigratesLegacyUser() async throws { + // Load the unmigrated legacy store + let account = LegacyRealmStore.Account.version2 + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + let legacyStore = try LegacyRealmStore.load(account: account) + XCTAssertTrue(LegacyRealmStore.hasData(for: account)) + XCTAssertEqual(legacyStore.cryptoVersion, .version2) + + // Build crypto and assert migration has been performed + let (crypto, hasMigrated) = try await buildCrypto(account: account) + XCTAssertNotNil(crypto) + XCTAssertTrue(hasMigrated) + + // Assert that data for the legacy store has been removed + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + } + + func test_migratesPartiallyMigratedUser() async throws { + // Load partially deprecated legacy store + let account = LegacyRealmStore.Account.deprecated1 + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + let legacyStore = try LegacyRealmStore.load(account: account) + XCTAssertTrue(LegacyRealmStore.hasData(for: account)) + XCTAssertEqual(legacyStore.cryptoVersion, .deprecated1) + + // Build crypto and assert migration has been performed + let (crypto, hasMigrated) = try await buildCrypto(account: account) + XCTAssertNotNil(crypto) + XCTAssertTrue(hasMigrated) + + // Assert that data for the legacy store has been removed + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + } + + func test_doesNotMigrateDeprecatedStore() async throws { + // Load fully deprecated legacy store + let account = LegacyRealmStore.Account.deprecated3 + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + let legacyStore = try LegacyRealmStore.load(account: account) + XCTAssertTrue(LegacyRealmStore.hasData(for: account)) + XCTAssertEqual(legacyStore.cryptoVersion, .deprecated3) + + // Build crypto and assert no migration has been performed + let (crypto, hasMigrated) = try await buildCrypto(account: .deprecated3) + XCTAssertNotNil(crypto) + XCTAssertFalse(hasMigrated) + + // Assert that data for the legacy store has been removed + XCTAssertFalse(LegacyRealmStore.hasData(for: account)) + } +} diff --git a/MatrixSDKTests/Crypto/MXSession+LegacyCrypto.swift b/MatrixSDKTests/Crypto/MXSession+LegacyCrypto.swift index 815fdd9887..c98d489229 100644 --- a/MatrixSDKTests/Crypto/MXSession+LegacyCrypto.swift +++ b/MatrixSDKTests/Crypto/MXSession+LegacyCrypto.swift @@ -28,7 +28,6 @@ import Foundation } guard let legacy = crypto as? MXLegacyCrypto else { - assertionFailure("Legacy crypto is not available, adjust test to not depend on legacy APIs") return nil } return legacy diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/LegacyRealmStore.swift b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/LegacyRealmStore.swift new file mode 100644 index 0000000000..4510c3a782 --- /dev/null +++ b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/LegacyRealmStore.swift @@ -0,0 +1,162 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Realm + +/// Class simulating legacy crypto store associated with the now-deprecated native crypto module +/// +/// It has access to several pre-made realm files with legacy accounts that can be loaded +/// and migrated to current crypto module +class LegacyRealmStore { + enum Error: Swift.Error { + case missingDependencies + } + + /// A few pre-created accounts with hardcoded details + enum Account { + + /// Realm store with crypto version `version2`, used for migration testing + case version2 + + /// Realm store with crypto version `deprecated1`, used for migration testing + case deprecated1 + + /// Realm store with crypto version `deprecated3`, used for migration testing + case deprecated3 + + /// Realm store with a verified accounts used to test cross-signing migration + case verified + + /// Realm store with an unverified accounts used to test cross-signing migration + case unverified + + /// File name for the associated account file + var fileName: String { + switch self { + case .version2: + return "legacy_version2_account" + case .deprecated1: + return "legacy_deprecated1_account" + case .deprecated3: + return "legacy_deprecated3_account" + case .verified: + return "legacy_verified_account" + case .unverified: + return "legacy_unverified_account" + } + } + + /// Hardcoded room id matching a given account + var roomId: String? { + switch self { + case .version2: + return nil + case .deprecated1: + return nil + case .deprecated3: + return nil + case .verified: + return "!QUWVMCIhJqIqTMLxof:x.y.z" + case .unverified: + return nil + } + } + + /// Hardcoded account credentials matching a given account + var credentials: MXCredentials { + let cred = MXCredentials() + switch self { + case .version2: + cred.userId = "@mxalice-54aeab93-b4b2-4edf-85e1-bc0dbbb710ee:x.y.z" + cred.deviceId = "NAHEYWCBBM" + case .deprecated1: + cred.userId = "@mxalice-d9eed33b-e269-4171-9352-8ee8b84b37a1:x.y.z" + cred.deviceId = "KLWNEPIHMX" + case .deprecated3: + cred.userId = "@mxalice-4c5a01ea-9fac-4568-bda6-09e2d14f0e5d:x.y.z" + cred.deviceId = "DCGBYVZFQI" + case .verified: + cred.userId = "@mxalice-107ca1c5-4d03-4ff4-affc-369f4ce6de6f:x.y.z" + cred.deviceId = "AXDAYKSETI" + case .unverified: + cred.userId = "@mxalice-f5314669-7d43-4662-8262-771728e1921f:x.y.z" + cred.deviceId = "ELSGFERWHH" + } + return cred + } + } + + static func load(account: Account) throws -> MXRealmCryptoStore { + guard + let sourceUrl = Bundle(for: Self.self).url(forResource: account.fileName, withExtension: "realm"), + let folder = realmFolder() + else { + throw Error.missingDependencies + } + + if !FileManager.default.fileExists(atPath: folder.path) { + try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true) + } + + let credentials = account.credentials + let file = "\(credentials.userId!)-\(credentials.deviceId!).realm" + + let targetUrl = folder.appendingPathComponent(file) + if FileManager.default.fileExists(atPath: targetUrl.path) { + try FileManager.default.removeItem(at: targetUrl) + } + + try FileManager.default.copyItem(at: sourceUrl, to: targetUrl) + return MXRealmCryptoStore(credentials: credentials) + } + + static func hasData(for account: Account) -> Bool { + let credentials = account.credentials + let file = "\(credentials.userId!)-\(credentials.deviceId!).realm" + + return MXRealmCryptoStore.hasData(for: credentials) + } + + static func deleteAllStores() throws { + guard let folder = realmFolder() else { + throw Error.missingDependencies + } + + if FileManager.default.fileExists(atPath: folder.path) { + try FileManager.default.removeItem(at: folder) + } + } + + private static func realmFolder() -> URL? { + platformDirectoryURL()? + .appendingPathComponent("MXRealmCryptoStore") + } + + private static func platformDirectoryURL() -> URL? { + #if os(OSX) + guard + let applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first, + let identifier = Bundle.main.bundleIdentifier + else { + return nil + } + return applicationSupport.appendingPathComponent(identifier) + #else + return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first + #endif + } +} diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/archived_encrypted_event b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/archived_encrypted_event new file mode 100644 index 0000000000..ba709102e8 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/archived_encrypted_event differ diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated1_account.realm b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated1_account.realm new file mode 100644 index 0000000000..1bad5afe95 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated1_account.realm differ diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated3_account.realm b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated3_account.realm new file mode 100644 index 0000000000..e1f4f07f61 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_deprecated3_account.realm differ diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_unverified_account.realm b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_unverified_account.realm new file mode 100644 index 0000000000..07a5593447 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_unverified_account.realm differ diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_verified_account.realm b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_verified_account.realm new file mode 100644 index 0000000000..f45e7546e4 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_verified_account.realm differ diff --git a/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_version2_account.realm b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_version2_account.realm new file mode 100644 index 0000000000..b02c1e73f7 Binary files /dev/null and b/MatrixSDKTests/Crypto/Migration/LegacyRealmStore/legacy_version2_account.realm differ diff --git a/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift b/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift deleted file mode 100644 index dff162d018..0000000000 --- a/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift +++ /dev/null @@ -1,331 +0,0 @@ -// -// Copyright 2023 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import MatrixSDKCrypto -@testable import MatrixSDK - -class MXCryptoMigrationV2Tests: XCTestCase { - enum Error: Swift.Error { - case missingDependencies - } - - class KeyProvider: NSObject, MXKeyProviderDelegate { - func isEncryptionAvailableForData(ofType dataType: String) -> Bool { - return true - } - - func hasKeyForData(ofType dataType: String) -> Bool { - return true - } - - func keyDataForData(ofType dataType: String) -> MXKeyData? { - MXRawDataKey(key: "1234".data(using: .ascii)!) - } - } - - var data: MatrixSDKTestsData! - var e2eData: MatrixSDKTestsE2EData! - - override func setUp() { - data = MatrixSDKTestsData() - e2eData = MatrixSDKTestsE2EData(matrixSDKTestsData: data) - } - - // MARK: - Helpers - - private func fullyMigratedOlmMachine(session: MXSession) throws -> MXCryptoMachine { - guard - let store = session.legacyCrypto?.store, - let restClient = session.matrixRestClient - else { - throw Error.missingDependencies - } - - MXKeyProvider.sharedInstance().delegate = KeyProvider() - let migration = MXCryptoMigrationV2(legacyStore: store) - try migration.migrateAllData { _ in } - let machine = try MXCryptoMachine( - userId: store.userId(), - deviceId: store.deviceId(), - restClient: restClient, - getRoomAction: { _ in - return nil - }) - MXKeyProvider.sharedInstance().delegate = nil - return machine - } - - private func partiallyMigratedOlmMachine(session: MXSession) throws -> MXCryptoMachine { - guard - let store = session.legacyCrypto?.store, - let restClient = session.matrixRestClient - else { - throw Error.missingDependencies - } - - MXKeyProvider.sharedInstance().delegate = KeyProvider() - let migration = MXCryptoMigrationV2(legacyStore: store) - try migration.migrateRoomAndGlobalSettingsOnly { _ in } - let machine = try MXCryptoMachine( - userId: store.userId(), - deviceId: store.deviceId(), - restClient: restClient, - getRoomAction: { _ in - return nil - }) - MXKeyProvider.sharedInstance().delegate = nil - return machine - } - - // MARK: - Tests - - func test_migratesAccountDetails() async throws { - let env = try await e2eData.startE2ETest() - let legacySession = env.session - - let machine = try self.fullyMigratedOlmMachine(session: env.session) - - XCTAssertEqual(machine.userId, legacySession.myUserId) - XCTAssertEqual(machine.deviceId, legacySession.myDeviceId) - XCTAssertEqual(machine.deviceCurve25519Key, legacySession.crypto.deviceCurve25519Key) - XCTAssertEqual(machine.deviceEd25519Key, legacySession.crypto.deviceEd25519Key) - - await env.close() - } - - func test_canDecryptMegolmMessageAfterMigration() async throws { - let env = try await e2eData.startE2ETest() - - guard let room = env.session.room(withRoomId: env.roomId) else { - throw Error.missingDependencies - } - - // Send a new message in encrypted room - let event = try await room.sendTextMessage("Hi bob") - - // Erase cleartext and make sure the event was indeed encrypted - event.setClearData(nil) - XCTAssertTrue(event.isEncrypted) - XCTAssertEqual(event.content["algorithm"] as? String, kMXCryptoMegolmAlgorithm) - XCTAssertNotNil(event.content["ciphertext"]) - - // Migrate the session to crypto v2 - let machine = try self.fullyMigratedOlmMachine(session: env.session) - - // Decrypt the event using crypto v2 - let decrypted = try machine.decryptRoomEvent(event) - let result = try MXEventDecryptionResult(event: decrypted) - let content = result.clearEvent["content"] as? [String: Any] - - // At this point we should be able to read back the original message after - // having decrypted the event with room keys migrated earlier - XCTAssertEqual(content?["body"] as? String, "Hi bob") - - await env.close() - } - - func test_notCrossSignedAfterMigration() async throws { - let env = try await e2eData.startE2ETest() - - // We start with user who cannot cross-sign (did not setup cross signing keys) - let legacyCrossSigning = env.session.crypto.crossSigning - XCTAssertFalse(legacyCrossSigning.canCrossSign) - XCTAssertFalse(legacyCrossSigning.hasAllPrivateKeys) - - // We then migrate the user into crypto v2 - let machine = try fullyMigratedOlmMachine(session: env.session) - let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: env.session.matrixRestClient) - try await crossSigningV2.refreshState() - - // As expected we cannot cross sign in v2 either - XCTAssertFalse(crossSigningV2.canCrossSign) - XCTAssertFalse(crossSigningV2.hasAllPrivateKeys) - - await env.close() - } - - func test_migratesCrossSigningStatus() async throws { - let env = try await e2eData.startE2ETest() - - // We start with user who setup cross-signing with password - let legacyCrossSigning = env.session.crypto.crossSigning - try await legacyCrossSigning.setup(withPassword: MXTESTS_ALICE_PWD) - XCTAssertTrue(legacyCrossSigning.canCrossSign) - XCTAssertTrue(legacyCrossSigning.hasAllPrivateKeys) - - // We now migrate the data into crypto v2 - let machine = try fullyMigratedOlmMachine(session: env.session) - let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: env.session.matrixRestClient) - try await crossSigningV2.refreshState() - - // And confirm that cross signing is ready - XCTAssertTrue(crossSigningV2.canCrossSign) - XCTAssertTrue(crossSigningV2.hasAllPrivateKeys) - - await env.close() - } - - func test_migratesRoomSettings() async throws { - let env = try await e2eData.startE2ETest() - - // We start with user and encrypted room with some settings - let legacyCrypto = env.session.crypto! - try await legacyCrypto.ensureEncryption(roomId: env.roomId) - legacyCrypto.setBlacklistUnverifiedDevicesInRoom(env.roomId, blacklist: true) - XCTAssertTrue(legacyCrypto.isRoomEncrypted(env.roomId)) - XCTAssertTrue(legacyCrypto.isBlacklistUnverifiedDevices(inRoom: env.roomId)) - - // We now migrate the data into crypto v2 - let machine = try fullyMigratedOlmMachine(session: env.session) - - // And confirm that room settings have been migrated - let settings = machine.roomSettings(roomId: env.roomId) - XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) - - await env.close() - } - - func test_migratesRoomSettingsInPartialMigration() async throws { - let env = try await e2eData.startE2ETest() - - // We start with user and encrypted room with some settings - let legacyCrypto = env.session.crypto! - try await legacyCrypto.ensureEncryption(roomId: env.roomId) - legacyCrypto.setBlacklistUnverifiedDevicesInRoom(env.roomId, blacklist: true) - XCTAssertTrue(legacyCrypto.isRoomEncrypted(env.roomId)) - XCTAssertTrue(legacyCrypto.isBlacklistUnverifiedDevices(inRoom: env.roomId)) - - // We now migrate the data into crypto v2 - let machine = try partiallyMigratedOlmMachine(session: env.session) - - // And confirm that room settings have been migrated - let settings = machine.roomSettings(roomId: env.roomId) - XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) - - await env.close() - } - - func test_migratesGlobalSettings() async throws { - let env1 = try await e2eData.startE2ETest() - env1.session.crypto.globalBlacklistUnverifiedDevices = true - let machine1 = try fullyMigratedOlmMachine(session: env1.session) - XCTAssertTrue(machine1.onlyAllowTrustedDevices) - await env1.close() - - let env2 = try await e2eData.startE2ETest() - env2.session.crypto.globalBlacklistUnverifiedDevices = false - let machine2 = try fullyMigratedOlmMachine(session: env2.session) - XCTAssertFalse(machine2.onlyAllowTrustedDevices) - await env2.close() - } - - func test_migratesGlobalSettingsInPartialMigration() async throws { - let env1 = try await e2eData.startE2ETest() - env1.session.crypto.globalBlacklistUnverifiedDevices = true - let machine1 = try partiallyMigratedOlmMachine(session: env1.session) - XCTAssertTrue(machine1.onlyAllowTrustedDevices) - await env1.close() - - let env2 = try await e2eData.startE2ETest() - env2.session.crypto.globalBlacklistUnverifiedDevices = false - let machine2 = try partiallyMigratedOlmMachine(session: env2.session) - XCTAssertFalse(machine2.onlyAllowTrustedDevices) - await env2.close() - } -} - -private extension MXCrypto { - func downloadKeys(userIds: [String]) async throws { - return try await withCheckedThrowingContinuation { continuation in - downloadKeys(userIds, forceDownload: false) { _, _ in - continuation.resume() - } - } - } - - func ensureEncryption(roomId: String) async throws { - return try await withCheckedThrowingContinuation { continuation in - ensureEncryption(inRoom: roomId) { - continuation.resume() - } - } - } -} - -extension MXCrossSigning { - func refreshState() async throws { - return try await withCheckedThrowingContinuation { continuation in - refreshState { _ in - continuation.resume() - } failure: { error in - continuation.resume(throwing: error) - } - } - } - - func signUser(userId: String) async throws { - return try await withCheckedThrowingContinuation { continuation in - signUser(withUserId: userId) { - continuation.resume() - } failure: { error in - continuation.resume(throwing: error) - } - } - } - - func setup(withPassword password: String) async throws { - return try await withCheckedThrowingContinuation { continuation in - setup(withPassword: password) { - continuation.resume() - } failure: { error in - continuation.resume(throwing: error) - } - } - } -} - -private extension MXRoom { - enum Error: Swift.Error { - case cannotSendMessage - } - - @MainActor - func sendTextMessage(_ text: String) async throws -> MXEvent { - var event: MXEvent? - _ = try await withCheckedThrowingContinuation{ (continuation: CheckedContinuation) in - sendTextMessage(text, localEcho: &event) { response in - switch response { - case .success(let value): - continuation.resume(returning: value) - case .failure(let error): - continuation.resume(throwing: error) - } - } - } - - guard let event = event else { - throw Error.cannotSendMessage - } - return event - } -} - -extension MXCryptoMigrationV2Tests: Logger { - func log(logLine: String) { - MXLog.debug("[MXCryptoMigrationV2Tests]: \(logLine)") - } -} diff --git a/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2UnitTests.swift b/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2UnitTests.swift new file mode 100644 index 0000000000..88b5cfc676 --- /dev/null +++ b/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2UnitTests.swift @@ -0,0 +1,167 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import MatrixSDKCrypto +@testable import MatrixSDK + +class MXCryptoMigrationV2UnitTests: XCTestCase { + enum Error: Swift.Error { + case missingEvent + } + + override func tearDown() async throws { + try LegacyRealmStore.deleteAllStores() + } + + // MARK: - Helpers + + private func fullyMigratedOlmMachine(legacyStore: MXCryptoStore) throws -> MXCryptoMachine { + MXKeyProvider.sharedInstance().delegate = MXKeyProviderStub() + let migration = MXCryptoMigrationV2(legacyStore: legacyStore) + try migration.migrateAllData { _ in } + let machine = try MXCryptoMachine( + userId: legacyStore.userId(), + deviceId: legacyStore.deviceId(), + restClient: MXRestClientStub(), + getRoomAction: { _ in + return nil + }) + MXKeyProvider.sharedInstance().delegate = nil + return machine + } + + private func partiallyMigratedOlmMachine(legacyStore: MXCryptoStore) throws -> MXCryptoMachine { + MXKeyProvider.sharedInstance().delegate = MXKeyProviderStub() + let migration = MXCryptoMigrationV2(legacyStore: legacyStore) + try migration.migrateRoomAndGlobalSettingsOnly { _ in } + let machine = try MXCryptoMachine( + userId: legacyStore.userId(), + deviceId: legacyStore.deviceId(), + restClient: MXRestClientStub(), + getRoomAction: { _ in + return nil + }) + MXKeyProvider.sharedInstance().delegate = nil + return machine + } + + private func loadEncryptedEvent() throws -> MXEvent { + guard let url = Bundle(for: Self.self).url(forResource: "archived_encrypted_event", withExtension: nil) else { + throw Error.missingEvent + } + + let data = try Data(contentsOf: url) + guard let event = NSKeyedUnarchiver.unarchiveObject(with: data) as? MXEvent else { + throw Error.missingEvent + } + return event + } + + // MARK: - Tests + + func test_migratesAccountDetails() throws { + let store = try LegacyRealmStore.load(account: .verified) + let machine = try fullyMigratedOlmMachine(legacyStore: store) + + XCTAssertEqual(machine.userId, store.userId()) + XCTAssertEqual(machine.deviceId, store.deviceId()) + XCTAssertNotNil(machine.deviceCurve25519Key) + XCTAssertEqual(machine.deviceCurve25519Key, store.account().identityKeys()[kMXKeyCurve25519Type] as? String) + XCTAssertNotNil(machine.deviceEd25519Key) + XCTAssertEqual(machine.deviceEd25519Key, store.account().identityKeys()[kMXKeyEd25519Type] as? String) + } + + func test_canDecryptMegolmMessageAfterMigration() throws { + // Load a previously archived and encrypted event + let event = try loadEncryptedEvent() + XCTAssertTrue(event.isEncrypted) + XCTAssertEqual(event.content["algorithm"] as? String, kMXCryptoMegolmAlgorithm) + XCTAssertNotNil(event.content["ciphertext"]) + + // Migrate data to crypto v2 + let store = try LegacyRealmStore.load(account: .verified) + let machine = try fullyMigratedOlmMachine(legacyStore: store) + + // Decrypt the event using crypto v2 + let decrypted = try machine.decryptRoomEvent(event) + let result = try MXEventDecryptionResult(event: decrypted) + let content = result.clearEvent["content"] as? [String: Any] + + // At this point we should be able to read back the original message after + // having decrypted the event with room keys migrated earlier + XCTAssertEqual(content?["body"] as? String, "Hi bob") + } + + func test_notCrossSignedAfterMigration() throws { + let store = try LegacyRealmStore.load(account: .unverified) + let machine = try fullyMigratedOlmMachine(legacyStore: store) + + let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: MXRestClientStub()) + XCTAssertFalse(crossSigningV2.canCrossSign) + XCTAssertFalse(crossSigningV2.hasAllPrivateKeys) + } + + func test_migratesCrossSigningStatus() throws { + let store = try LegacyRealmStore.load(account: .verified) + let machine = try fullyMigratedOlmMachine(legacyStore: store) + + let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: MXRestClientStub()) + XCTAssertTrue(crossSigningV2.hasAllPrivateKeys) + } + + func test_migratesRoomSettings() throws { + let store = try LegacyRealmStore.load(account: .verified) + let machine = try fullyMigratedOlmMachine(legacyStore: store) + + let settings = machine.roomSettings(roomId: LegacyRealmStore.Account.verified.roomId!) + XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) + } + + func test_migratesRoomSettingsInPartialMigration() throws { + let store = try LegacyRealmStore.load(account: .verified) + let machine = try partiallyMigratedOlmMachine(legacyStore: store) + + let settings = machine.roomSettings(roomId: LegacyRealmStore.Account.verified.roomId!) + XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) + } + + func test_migratesGlobalSettings() throws { + let store1 = try LegacyRealmStore.load(account: .unverified) + let machine1 = try fullyMigratedOlmMachine(legacyStore: store1) + XCTAssertTrue(machine1.onlyAllowTrustedDevices) + + let store2 = try LegacyRealmStore.load(account: .verified) + let machine2 = try fullyMigratedOlmMachine(legacyStore: store2) + XCTAssertFalse(machine2.onlyAllowTrustedDevices) + } + + func test_migratesGlobalSettingsInPartialMigration() throws { + let store1 = try LegacyRealmStore.load(account: .unverified) + let machine1 = try partiallyMigratedOlmMachine(legacyStore: store1) + XCTAssertTrue(machine1.onlyAllowTrustedDevices) + + let store2 = try LegacyRealmStore.load(account: .verified) + let machine2 = try partiallyMigratedOlmMachine(legacyStore: store2) + XCTAssertFalse(machine2.onlyAllowTrustedDevices) + } +} + +extension MXCryptoMigrationV2UnitTests: Logger { + func log(logLine: String) { + MXLog.debug("[MXCryptoMigrationV2Tests]: \(logLine)") + } +} diff --git a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift index 4854950d36..1af4801107 100644 --- a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift @@ -128,7 +128,7 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { func test_cancelledByMeState() { let request = makeRequest() - request.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: true))) + request.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: true))) XCTAssertEqual(request.reasonCancelCode?.value, "123") XCTAssertEqual(request.reasonCancelCode?.humanReadable, "Changed mind") @@ -138,7 +138,7 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { func test_cancelledByThemState() { let request = makeRequest() - request.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: false))) + request.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: false))) XCTAssertEqual(request.reasonCancelCode?.value, "123") XCTAssertEqual(request.reasonCancelCode?.humanReadable, "Changed mind") diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2UnitTests.swift index 61bf513aeb..1ed48469fd 100644 --- a/MatrixSDKTests/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Transactions/QRCode/MXQRCodeTransactionV2UnitTests.swift @@ -101,7 +101,7 @@ class MXQRCodeTransactionV2UnitTests: XCTestCase { func test_cancelledByMeState() { let transaction = makeTransaction() - transaction.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: true))) + transaction.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: true))) XCTAssertEqual(transaction.reasonCancelCode?.value, "123") XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") @@ -111,7 +111,7 @@ class MXQRCodeTransactionV2UnitTests: XCTestCase { func test_cancelledByThemState() { let transaction = makeTransaction() - transaction.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: false))) + transaction.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: false))) XCTAssertEqual(transaction.reasonCancelCode?.value, "123") XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift index fa45ff94a2..ad1ba7166f 100644 --- a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift @@ -117,7 +117,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { func test_cancelledByMeState() { let transaction = makeTransaction() - transaction.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: true))) + transaction.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: true))) XCTAssertEqual(transaction.reasonCancelCode?.value, "123") XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") @@ -127,7 +127,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { func test_cancelledByThemState() { let transaction = makeTransaction() - transaction.onChange(state: .cancelled(cancelInfo: .init(cancelCode: "123", reason: "Changed mind", cancelledByUs: false))) + transaction.onChange(state: .cancelled(cancelInfo: .init(reason: "Changed mind", cancelCode: "123", cancelledByUs: false))) XCTAssertEqual(transaction.reasonCancelCode?.value, "123") XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") diff --git a/MatrixSDKTests/JSONModels/MXKeysQueryResponseUnitTests.swift b/MatrixSDKTests/JSONModels/MXKeysQueryResponseUnitTests.swift index bdd834d29c..2c6ca52044 100644 --- a/MatrixSDKTests/JSONModels/MXKeysQueryResponseUnitTests.swift +++ b/MatrixSDKTests/JSONModels/MXKeysQueryResponseUnitTests.swift @@ -51,15 +51,15 @@ class MXKeysQueryResponseUnitTests: XCTestCase { usage: ["master"], keys: "\(userId)-MSK" ).jsonString(), - selfSigningKey: MXCrossSigningKey( - userId: userId, - usage: ["self_signing"], - keys: "\(userId)-SSK" - ).jsonString(), userSigningKey: MXCrossSigningKey( userId: userId, usage: ["user_signing"], keys: "\(userId)-USK" + ).jsonString(), + selfSigningKey: MXCrossSigningKey( + userId: userId, + usage: ["self_signing"], + keys: "\(userId)-SSK" ).jsonString() ), isVerified: true diff --git a/MatrixSDKTests/MXBaseKeyBackupTests.m b/MatrixSDKTests/MXBaseKeyBackupTests.m index 5cdca88f5b..94ec9b427a 100644 --- a/MatrixSDKTests/MXBaseKeyBackupTests.m +++ b/MatrixSDKTests/MXBaseKeyBackupTests.m @@ -757,8 +757,7 @@ - (void)testRestoreKeyBackup - Try to restore the e2e backup with a wrong recovery key - It must fail */ -// TODO: test is currently broken -- (void)xtestRestoreKeyBackupWithAWrongRecoveryKey +- (void)testRestoreKeyBackupWithAWrongRecoveryKey { // - Do an e2e backup to the homeserver with a recovery key // - Log Alice on a new device @@ -824,8 +823,7 @@ - (void)testRestoreKeyBackupWithPassword - Try to restore the e2e backup with a wrong password - It must fail */ -// TODO: test is currently broken -- (void)xtestRestoreKeyBackupWithAWrongPassword +- (void)testRestoreKeyBackupWithAWrongPassword { // - Do an e2e backup to the homeserver with a password // - Log Alice on a new device @@ -891,8 +889,7 @@ - (void)testUseRecoveryKeyToRestoreAPasswordKeyKeyBackup - Try to restore the e2e backup with a password - It must fail */ -// TODO: test is currently broken -- (void)xtestUsePasswordToRestoreARecoveryKeyKeyBackup +- (void)testUsePasswordToRestoreARecoveryKeyKeyBackup { // - Do an e2e backup to the homeserver with a recovery key // - And log Alice on a new device @@ -927,8 +924,7 @@ - (void)xtestUsePasswordToRestoreARecoveryKeyKeyBackup - Restart alice session -> The new alice session must back up to the same version */ -// TODO: test is currently broken -- (void)xtestCheckAndStartKeyBackupWhenRestartingAMatrixSession +- (void)testCheckAndStartKeyBackupWhenRestartingAMatrixSession { // - Create a backup version [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -1296,8 +1292,7 @@ - (void)testTrustKeyBackupVersionWithRecoveryKey - It must fail - The backup must still be untrusted and disabled */ -// TODO: test is currently broken -- (void)xtestTrustKeyBackupVersionWithWrongRecoveryKey +- (void)testTrustKeyBackupVersionWithWrongRecoveryKey { // - Do an e2e backup to the homeserver with a recovery key // - And log Alice on a new device @@ -1390,8 +1385,7 @@ - (void)testTrustKeyBackupVersionWithPassword - It must fail - The backup must still be untrusted and disabled */ -// TODO: test is currently broken -- (void)xtestTrustKeyBackupVersionWithWrongPassword +- (void)testTrustKeyBackupVersionWithWrongPassword { NSString *password = @"password"; diff --git a/MatrixSDKTests/MXCrossSigningTests.m b/MatrixSDKTests/MXCrossSigningTests.m index e311648759..fc52eb39a1 100644 --- a/MatrixSDKTests/MXCrossSigningTests.m +++ b/MatrixSDKTests/MXCrossSigningTests.m @@ -977,8 +977,7 @@ - (void)testTrustsBetweenBobAndAliceWithTwoDevices // -> Alice2 should see Alice1 as trusted thanks to cross-signing // -> Bob should see Alice3 as trusted thanks to cross-signing // -> Alice3 should see Bob as trusted thanks to cross-signing -// TODO: test is currently broken -- (void)xtestTrustChain +- (void)testTrustChain { // - Have Alice with 2 devices (Alice1 and Alice2) and Bob. All trusted via cross-signing [matrixSDKTestsE2EData doTestWithBobAndAliceWithTwoDevicesAllTrusted:self readyToTest:^(MXSession *aliceSession1, MXSession *aliceSession2, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -1230,8 +1229,7 @@ - (void)testMXCrossSigningResetDetection // - Reset XS on this new device // - Restart Alice first device // -> Alice first device must not trust the cross-signing anymore -// TODO: test is currently broken -- (void)xtestMXCrossSigningResetDetectionAfterRestart +- (void)testMXCrossSigningResetDetectionAfterRestart { // - Have Alice with cross-signing [self doTestWithBobAndBootstrappedAlice:self readyToTest:^(MXSession *bobSession, MXSession *aliceSession, NSString *roomId, XCTestExpectation *expectation) { diff --git a/MatrixSDKTests/MXCrossSigningVerificationTests.m b/MatrixSDKTests/MXCrossSigningVerificationTests.m index 2d38c3d957..c2aecc60ef 100644 --- a/MatrixSDKTests/MXCrossSigningVerificationTests.m +++ b/MatrixSDKTests/MXCrossSigningVerificationTests.m @@ -383,8 +383,7 @@ - (void)testSelfVerificationWithSAS -> Both ends must get a done message - Then, test MXKeyVerification */ -// TODO: test is currently broken -- (void)xtestVerificationByDMFullFlow +- (void)testVerificationByDMFullFlow { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -616,8 +615,7 @@ - (void)xtestVerificationByDMFullFlow -> Both ends must get a done message - Then, test MXKeyVerification */ -// TODO: test is currently broken -- (void)xtestVerifyingAnotherUserQRCodeVerificationFullFlow +- (void)testVerifyingAnotherUserQRCodeVerificationFullFlow { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { diff --git a/MatrixSDKTests/MXCryptoKeyVerificationTests.m b/MatrixSDKTests/MXCryptoKeyVerificationTests.m index 08b3a7c81e..c803b60442 100644 --- a/MatrixSDKTests/MXCryptoKeyVerificationTests.m +++ b/MatrixSDKTests/MXCryptoKeyVerificationTests.m @@ -369,8 +369,7 @@ - (void)checkVerificationByToDeviceFullFlowWithBobSession:(MXSession*)bobSession }]; } -// TODO: test is currently broken -- (void)xtestVerificationByToDeviceFullFlow +- (void)testVerificationByToDeviceFullFlow { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -412,8 +411,7 @@ - (void)testVerificationByToDeviceFullFlowWith2Devices /** Same tests as testVerificationByToDeviceFullFlow but with only alice verifying her 2 devices. */ -// TODO: test is currently broken -- (void)xtestVerificationByToDeviceSelfVerificationFullFlow +- (void)testVerificationByToDeviceSelfVerificationFullFlow { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -457,12 +455,6 @@ - (void)testVerificationByToDeviceRequestCancellation success:^(id requestFromAliceDevice1POV) { // -> The other device list should have been computed well - if (MXSDKOptions.sharedInstance.enableCryptoSDK) - { - XCTFail(@"This test uses `MXKeyVerificationByToDeviceRequest` which is only compatible with Crypto V1. Replace assertions to make it compatible with V2 as well"); - [expectation fulfill]; - return; - } MXKeyVerificationByToDeviceRequest *toDeviceRequestFromAliceDevice1POV = (MXKeyVerificationByToDeviceRequest*)requestFromAliceDevice1POV; XCTAssertNotNil(toDeviceRequestFromAliceDevice1POV.requestedOtherDeviceIds); NSSet *expectedRequestedDevices = [NSSet setWithArray:@[aliceSession2DeviceId, aliceSession3DeviceId]]; @@ -563,8 +555,7 @@ - (void)testVerificationByToDeviceRequestWithNoOtherDevice -> Alice gets the requests notification -> They both have it in their pending requests */ -// TODO: test is currently broken -- (void)xtestVerificationByDMRequests +- (void)testVerificationByDMRequests { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -611,8 +602,7 @@ - (void)xtestVerificationByDMRequests /** Nomical case: The full flow */ -// TODO: test is currently broken -- (void)xtestVerificationByDMFullFlow +- (void)testVerificationByDMFullFlow { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -1016,8 +1006,7 @@ - (void)testVerificationByDMWithRoomDetection -> Alice gets the requests notification -> They both have it in their pending requests */ -// TODO: test is currently broken -- (void)xtestVerificationByDMWithNoRoom +- (void)testVerificationByDMWithNoRoom { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithBobAndAlice:self readyToTest:^(MXSession *aliceSession, MXSession *bobSession, XCTestExpectation *expectation) { @@ -1075,8 +1064,7 @@ - (void)xtestVerificationByDMWithNoRoom /** Same tests as testVerificationByDMFullFlow but with alice with 2 sessions */ -// TODO: test is currently broken -- (void)xtestVerificationByDMWithAliceWith2Devices +- (void)testVerificationByDMWithAliceWith2Devices { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -1091,8 +1079,7 @@ - (void)xtestVerificationByDMWithAliceWith2Devices /** Same tests as testVerificationByDMFullFlow but with bob with 2 sessions */ -// TODO: test is currently broken -- (void)xtestVerificationByDMWithAUserWith2Devices +- (void)testVerificationByDMWithAUserWith2Devices { // - Alice and Bob are in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:YES aliceStore:[[MXMemoryStore alloc] init] bobStore:[[MXMemoryStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { diff --git a/MatrixSDKTests/MXCryptoSecretShareTests.m b/MatrixSDKTests/MXCryptoSecretShareTests.m index f5763032a9..63f07c624b 100644 --- a/MatrixSDKTests/MXCryptoSecretShareTests.m +++ b/MatrixSDKTests/MXCryptoSecretShareTests.m @@ -114,7 +114,7 @@ - (void)testSecretShare // -> She gets the secret XCTAssertEqualObjects(sharedSecret, secret); [expectation fulfill]; - + return YES; } failure:^(NSError * _Nonnull error) { XCTFail(@"The operation should not fail - NSError: %@", error); [expectation fulfill]; diff --git a/MatrixSDKTests/MXCryptoShareTests.m b/MatrixSDKTests/MXCryptoShareTests.m index 6c60b9588a..5f96246e84 100644 --- a/MatrixSDKTests/MXCryptoShareTests.m +++ b/MatrixSDKTests/MXCryptoShareTests.m @@ -142,8 +142,7 @@ - (void)createScenario:(void (^)(MXSession *aliceSession, NSString *roomId, MXMe -> Key share requests must be pending -> Then, they must have been sent */ -// TODO: Test currently broken -- (void)xtestKeyShareRequestFromNewDevice +- (void)testKeyShareRequestFromNewDevice { // - Have Alice and Bob in e2ee room with messages [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -194,8 +193,7 @@ - (void)xtestKeyShareRequestFromNewDevice -> After a bit, Alice2 should have received all keys -> Key share requests should have complete */ -// TODO: test is currently broken -- (void)xtestNominalCase +- (void)testNominalCase { // - Have Alice and Bob in e2ee room with messages [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -271,8 +269,7 @@ - (void)xtestNominalCase - Enable key share requests on Alice2 -> Key share requests should have complete */ -// TODO: test currently broken -- (void)xtestDisableKeyShareRequest +- (void)testDisableKeyShareRequest { // - Have Alice and Bob in e2ee room with messages [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -354,8 +351,7 @@ - (void)xtestDisableKeyShareRequest -> key share requests on Alice2 are enabled again -> No m.room_key_request have been made */ -// TODO: Test currently broken -- (void)xtestNoKeyShareRequestIfThereIsABackup +- (void)testNoKeyShareRequestIfThereIsABackup { // - Have Alice and Bob in e2ee room with messages [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -676,8 +672,7 @@ - (void)testShareHistoryKeysWithInvitedUser - Alice invites Bob into the room from her second device -> Bob has recieved only 2 session keys, namely those with `sharedHistory` set to true */ -// TODO: test is currently broken -- (void)xtestSharedHistoryPreservedWhenForwardingKeys +- (void)testSharedHistoryPreservedWhenForwardingKeys { [matrixSDKTestsE2EData doE2ETestWithAliceInARoom:self andStore:[[MXMemoryStore alloc] init] diff --git a/MatrixSDKTests/MXCryptoTests.m b/MatrixSDKTests/MXCryptoTests.m index 1cd1fb68ae..36b50f5138 100644 --- a/MatrixSDKTests/MXCryptoTests.m +++ b/MatrixSDKTests/MXCryptoTests.m @@ -111,18 +111,15 @@ - (void)testEnableCrypto XCTAssertNil(mxSession.crypto, @"Crypto is disabled by default"); - XCTAssertFalse([mxSession.legacyCrypto.store.class hasDataForCredentials:mxSession.matrixRestClient.credentials]); - + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; [mxSession enableCrypto:YES success:^{ + MXKeyProvider.sharedInstance.delegate = nil; XCTAssert(mxSession.crypto); - XCTAssert([mxSession.legacyCrypto.store.class hasDataForCredentials:mxSession.matrixRestClient.credentials]); [mxSession enableCrypto:NO success:^{ XCTAssertNil(mxSession.crypto); - XCTAssertFalse([mxSession.legacyCrypto.store.class hasDataForCredentials:mxSession.matrixRestClient.credentials], @"Crypto data must have been trashed"); - [expectation fulfill]; } failure:^(NSError *error) { @@ -140,19 +137,18 @@ - (void)testEnableCrypto - (void)testMXSDKOptionsEnableCryptoWhenOpeningMXSession { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; [matrixSDKTestsData doMXSessionTestWithBob:self readyToTest:^(MXSession *mxSession, XCTestExpectation *expectation) { // Reset the option to not disturb other tests [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; XCTAssert(mxSession.crypto); - XCTAssert([mxSession.legacyCrypto.store.class hasDataForCredentials:mxSession.matrixRestClient.credentials]); [mxSession enableCrypto:NO success:^{ XCTAssertNil(mxSession.crypto); - XCTAssertFalse([mxSession.legacyCrypto.store.class hasDataForCredentials:mxSession.matrixRestClient.credentials], @"Crypto data must have been trashed"); - [expectation fulfill]; } failure:^(NSError *error) { @@ -237,8 +233,7 @@ - (void)testCryptoPersistenceInStore }]; } -// TODO: Test currently broken -- (void)xtestMultipleDownloadKeys +- (void)testMultipleDownloadKeys { [matrixSDKTestsE2EData doE2ETestWithBobAndAlice:self readyToTest:^(MXSession *bobSession, MXSession *aliceSession, XCTestExpectation *expectation) { @@ -882,8 +877,7 @@ - (void)testAliceAndBobInACryptedRoomBackPaginationFromMemoryStore }]; } -// TODO: Test currently broken -- (void)xtestAliceAndBobInACryptedRoomBackPaginationFromHomeServer +- (void)testAliceAndBobInACryptedRoomBackPaginationFromHomeServer { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -1323,8 +1317,7 @@ - (void)testAliceAndBlockedBob // Alice sends a message #5 // Check that the message can be decrypted by the Bob's device and the Sam's device -// TODO: Test currently broken -- (void)xtestBlackListUnverifiedDevices +- (void)testBlackListUnverifiedDevices { NSArray *aliceMessages = @[ @"0", @@ -2056,8 +2049,7 @@ - (void)testRoomKeyReshare }]; } -// TODO: Test currently broken -- (void)xtestLateRoomKey +- (void)testLateRoomKey { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:NO readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -2133,8 +2125,7 @@ - (void)xtestLateRoomKey // -> The third event must fail to decrypt at first because Bob the olm session is wedged // -> This is automatically fixed after SDKs restarted the olm session -// TODO: Test currently broken -- (void)xtestOlmSessionUnwedging +- (void)testOlmSessionUnwedging { // - Alice & Bob have messages in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:NO aliceStore:[[MXFileStore alloc] init] bobStore:[[MXFileStore alloc] init] readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -2948,8 +2939,7 @@ - (void)testIncomingRoomKeyRequest - 3- Alice sends a second message -> 4- It must be sent (it was never sent before the fix) */ -// TODO: test is currently broken -- (void)xtestDeviceInvalidationWhileSending +- (void)testDeviceInvalidationWhileSending { [matrixSDKTestsE2EData doE2ETestWithAliceInARoom:self readyToTest:^(MXSession *aliceSession, NSString *roomId, XCTestExpectation *expectation) { @@ -3079,8 +3069,7 @@ - (void)testRestoreOlmOutboundKey - close current session and open a new session - Restore the outbound group session for the current room and check it exists and contains the new key */ -// TODO: test is currently broken -- (void)xtestDiscardAndRestoreOlmOutboundKey +- (void)testDiscardAndRestoreOlmOutboundKey { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { MXOlmOutboundGroupSession *outboundSession = [aliceSession.legacyCrypto.store outboundGroupSessionWithRoomId:roomId]; diff --git a/MatrixSDKTests/MXCurve25519KeyBackupTests.m b/MatrixSDKTests/MXCurve25519KeyBackupTests.m deleted file mode 100644 index 346ff3a07f..0000000000 --- a/MatrixSDKTests/MXCurve25519KeyBackupTests.m +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright 2022 The Matrix.org Foundation C.I.C - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "MXBaseKeyBackupTests.h" - -#import "MXCrypto_Private.h" -#import "MXCryptoStore.h" -#import "MXRecoveryKey.h" -#import "MXKeybackupPassword.h" -#import "MXOutboundSessionInfo.h" -#import "MXCrossSigning_Private.h" -#import "MXCurve25519BackupAuthData.h" -#import "MXCurve25519KeyBackupAlgorithm.h" - -// Do not bother with retain cycles warnings in tests -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-retain-cycles" - -@interface MXCurve25519KeyBackupTests : MXBaseKeyBackupTests - -@end - -@implementation MXCurve25519KeyBackupTests - -- (NSString *)algorithm -{ - return kMXCryptoCurve25519KeyBackupAlgorithm; -} - -- (BOOL)isUntrusted -{ - return MXCurve25519KeyBackupAlgorithm.isUntrusted; -} - -- (MXKeyBackupVersion*)fakeKeyBackupVersion -{ - return [MXKeyBackupVersion modelFromJSON:@{ - @"algorithm": self.algorithm, - @"auth_data": @{ - @"public_key": @"abcdefg", - @"signatures": @{ - @"something": @{ - @"ed25519:something": @"hijklmnop" - } - } - } - }]; -} - -/** - Check that `[MXKeyBackup prepareKeyBackupVersion]` uses Curve25519 algorithm by default - */ -- (void)testPrepareKeyBackupVersionWithDefaultAlgorithm -{ - [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - - XCTAssertNotNil(aliceSession.crypto.backup); - XCTAssertFalse(aliceSession.crypto.backup.enabled); - - // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { - - XCTAssertNotNil(keyBackupCreationInfo); - XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); - XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); - MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; - XCTAssertNotNil(authData.publicKey); - XCTAssertNotNil(authData.signatures); - XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); - - [expectation fulfill]; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }]; -} - -/** - Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - */ -- (void)testPrepareKeyBackupVersion -{ - [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - - XCTAssertNotNil(aliceSession.crypto.backup); - XCTAssertFalse(aliceSession.crypto.backup.enabled); - - // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { - - XCTAssertNotNil(keyBackupCreationInfo); - XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); - XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); - MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; - XCTAssertNotNil(authData.publicKey); - XCTAssertNotNil(authData.signatures); - XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); - - [expectation fulfill]; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }]; -} - -@end - -#pragma clang diagnostic pop diff --git a/MatrixSDKTests/MXDehydrationTests.m b/MatrixSDKTests/MXDehydrationTests.m deleted file mode 100644 index effa122d2b..0000000000 --- a/MatrixSDKTests/MXDehydrationTests.m +++ /dev/null @@ -1,527 +0,0 @@ -// -// Copyright 2021 The Matrix.org Foundation C.I.C -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import - -#import "MatrixSDKTestsData.h" -#import "MatrixSDKTestsE2EData.h" - -#import "MXSession.h" -#import "MXCrypto_Private.h" -#import "MXCrossSigning_Private.h" - -#import "MXSDKOptions.h" - -#import "MXKeyProvider.h" -#import "MXAesKeyData.h" -#import "MXRawDataKey.h" - -#import -#import "MXDehydrationService.h" -#import "MatrixSDKTestsSwiftHeader.h" - -// Do not bother with retain cycles warnings in tests -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-retain-cycles" - -@interface MXDehydrationTests : XCTestCase - -@property (nonatomic, strong) MatrixSDKTestsData *matrixSDKTestsData; -@property (nonatomic, strong) MatrixSDKTestsE2EData *matrixSDKTestsE2EData; - -@property (nonatomic, strong) NSData *dehydrationKey; - -@property (nonatomic, strong) MXDehydrationService *dehydrationService; - -@end - -@implementation MXDehydrationTests - -- (void)setUp -{ - [super setUp]; - - _matrixSDKTestsData = [[MatrixSDKTestsData alloc] init]; - _matrixSDKTestsE2EData = [[MatrixSDKTestsE2EData alloc] initWithMatrixSDKTestsData:_matrixSDKTestsData]; - - _dehydrationKey = [@"6fXK17pQFUrFqOnxt3wrqz8RHkQUT9vQ" dataUsingEncoding:NSUTF8StringEncoding]; - _dehydrationService = [MXDehydrationService new]; -} - -- (void)tearDown -{ - _matrixSDKTestsData = nil; - _matrixSDKTestsE2EData = nil; - _dehydrationService = nil; - - [super tearDown]; -} - -// Check device dehydration -// - Have e2e Alice -// - Alice creates a dehydrated device -// - Alice downloads their own devices keys -// -> Alice must see their dehydrated device --(void)testDehydrateDevice -{ - // - Have e2e Alice - MXWeakify(self); - [self.matrixSDKTestsE2EData doE2ETestWithAliceInARoom:self readyToTest:^(MXSession *mxSession, NSString *roomId, XCTestExpectation *expectation) { - MXStrongifyAndReturnIfNil(self); - [mxSession.crypto.crossSigning setupWithPassword:MXTESTS_ALICE_PWD success:^{ - - // - Alice creates a dehydrated device - [self.dehydrationService dehydrateDeviceWithMatrixRestClient:mxSession.matrixRestClient crossSigning:mxSession.legacyCrypto.legacyCrossSigning dehydrationKey:self.dehydrationKey success:^(NSString *dehydratedDeviceId) { - // - Alice downloads their own devices keys - [mxSession.crypto downloadKeys:@[mxSession.myUserId] forceDownload:YES success:^(MXUsersDevicesMap *usersDevicesInfoMap, NSDictionary *crossSigningKeysMap) { - - // -> Alice must see her dehydrated device - XCTAssertEqual([usersDevicesInfoMap deviceIdsForUser:mxSession.myUserId].count, 2); - - MXDeviceInfo *dehydratedDevice = [usersDevicesInfoMap objectForDevice:dehydratedDeviceId forUser:mxSession.myUserId]; - XCTAssertNotNil(dehydratedDevice); - XCTAssertEqualObjects(dehydratedDevice.deviceId, dehydratedDeviceId); - XCTAssertTrue([mxSession.legacyCrypto.legacyCrossSigning isDeviceVerified:dehydratedDevice]); - - [expectation fulfill]; - } failure:^(NSError * error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError * error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError * error) { - XCTFail(@"Failed setting up cross-signing with error: %@", error); - [expectation fulfill]; - }]; - }]; -} - -// Check that others can see a dehydrated device -// - Alice and Bob are in an e2e room -// - Bob creates a dehydrated device and logs out -// - Alice downloads Bob's devices keys -// -> Alice must see Bob's dehydrated device --(void)testDehydrateDeviceSeenByOther -{ - // - Alice and Bob are in an e2e room - [self.matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:NO readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [bobSession.crypto.crossSigning setupWithPassword:MXTESTS_BOB_PWD success:^{ - - NSString *bobUserId = bobSession.myUserId; - - // - Bob creates a dehydrated device and logs out - [self.dehydrationService dehydrateDeviceWithMatrixRestClient:bobSession.matrixRestClient crossSigning:bobSession.legacyCrypto.legacyCrossSigning dehydrationKey:self.dehydrationKey success:^(NSString *bobDehydratedDeviceId) { - dispatch_async(dispatch_get_main_queue(), ^{ - [bobSession logout:^{ - - // - Alice download Bob's devices keys - [aliceSession.crypto downloadKeys:@[bobUserId] forceDownload:YES success:^(MXUsersDevicesMap *usersDevicesInfoMap, NSDictionary *crossSigningKeysMap) { - - NSLog(@"[MXCryptoTest] User devices: %@", [usersDevicesInfoMap deviceIdsForUser:bobUserId]); - - // -> Alice must see Bob's dehydrated device - XCTAssertEqual([usersDevicesInfoMap deviceIdsForUser:bobUserId].count, 1); - - MXDeviceInfo *bobDehydratedDevice = [usersDevicesInfoMap objectForDevice:bobDehydratedDeviceId forUser:bobUserId]; - XCTAssertNotNil(bobDehydratedDevice); - XCTAssertEqualObjects(bobDehydratedDevice.deviceId, bobDehydratedDeviceId); - - [expectation fulfill]; - - } failure:^(NSError * error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError * error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - }); - } failure:^(NSError * error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError * error) { - XCTFail(@"Failed setting up cross-signing with error: %@", error); - }]; - }]; -} - -// Check that device rehydration fails silently if no dehydrated device exists -// - Bob logs in (no device dehydration) -// - Bob tries to rehydrate a device -// -> Bob should start his session normally --(void)testDeviceRehydrationWithoutDehydratedDevice -{ - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; - - // - Bob logs in (no device dehydration) - [self.matrixSDKTestsData doMXRestClientTestWithBob:self readyToTest:^(MXRestClient *bobRestClient, XCTestExpectation *expectation) { - MXSession *mxSession = [[MXSession alloc] initWithMatrixRestClient:bobRestClient]; - [self.matrixSDKTestsData retain:mxSession]; - - // - Bob tries to rehydrate a device - [self.dehydrationService rehydrateDeviceWithMatrixRestClient:mxSession.matrixRestClient dehydrationKey:self.dehydrationKey success:^(NSString *deviceId) { - XCTFail(@"No rehydrated device should be found."); - [expectation fulfill]; - - } failure:^(NSError *error) { - if ([error.domain isEqual:MXDehydrationServiceErrorDomain] && error.code == MXDehydrationServiceNothingToRehydrateErrorCode) - { - [mxSession start:^{ - // -> Bob should start his session normally - [expectation fulfill]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } - else - { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - } - }]; - }]; -} - -// Check if a dehydrated device can be properly rehydrated -// - Alice is in an e2e room -// - Alice setup a dehydrated device -// - Alice logs off and logs in back -// - Alice rehydrate her device -// -> The rehydrated device must have the same properties --(void)testDehydrateDeviceAndClaimDehydratedDevice -{ - // - Alice is in an e2e room - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [self.matrixSDKTestsE2EData doE2ETestWithAliceInARoom:self readyToTest:^(MXSession *aliceSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.crossSigning setupWithPassword:MXTESTS_ALICE_PWD success:^{ - - NSString *aliceSessionDevice = aliceSession.myDeviceId; - // - Alice setup a dehydrated device - [self.dehydrationService dehydrateDeviceWithMatrixRestClient:aliceSession.matrixRestClient crossSigning:aliceSession.legacyCrypto.legacyCrossSigning dehydrationKey:self.dehydrationKey success:^(NSString *dehydratedDeviceId) { - dispatch_async(dispatch_get_main_queue(), ^{ - // - Alice logs off and logs in back - [self.matrixSDKTestsData loginUserOnANewDevice:self credentials:nil withPassword:MXTESTS_ALICE_PWD sessionToLogout:aliceSession newSessionStore:nil startNewSession:NO e2e:YES onComplete:^(MXSession *aliceSession2) { - - NSString *aliceSession2Device = aliceSession2.myDeviceId; - // - Alice rehydrate her device - [self.dehydrationService rehydrateDeviceWithMatrixRestClient:aliceSession2.matrixRestClient dehydrationKey:self.dehydrationKey success:^(NSString *deviceId) { - // -> The rehydrated device must have the same properties - if (!deviceId) - { - XCTFail(@"device rehydration shouldn't be canceled"); - [expectation fulfill]; - return; - } - aliceSession2.credentials.deviceId = deviceId; - - XCTAssertNotEqualObjects(aliceSessionDevice, aliceSession2Device); - XCTAssertNotEqualObjects(aliceSession2Device, dehydratedDeviceId); - XCTAssertNotEqualObjects(aliceSession2.myDeviceId, aliceSession2Device); - XCTAssertEqualObjects(aliceSession2.myDeviceId, dehydratedDeviceId); - - [aliceSession2 start:^{ - XCTAssertNotNil(aliceSession2.crypto); - XCTAssertEqualObjects(aliceSession2.legacyCrypto.myDevice.deviceId, dehydratedDeviceId); - XCTAssertEqualObjects(aliceSession2.legacyCrypto.store.deviceId, dehydratedDeviceId); - XCTAssertTrue([aliceSession2.crypto.crossSigning canTrustCrossSigning]); - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - [expectation fulfill]; - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - }]; - }); - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Failed setting up cross-signing with error: %@", error); - }]; - }]; -} - -// Check that a user can receive live message with a rehydrated session -// - Alice and Bob are in an e2e room -// - Alice creates a dehydrated device -// - Alice logs out and logs on -// - Alice rehydrates the new session with the dehydrated device -// - And starts her new session with e2e enabled -// - Bob sends a message -// -> Alice must be able to receive and decrypt the message sent by Bob --(void)testReceiveLiveMessageAfterDeviceRehydration -{ - // - Alice and Bob are in an e2e room - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [self.matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.crossSigning setupWithPassword:MXTESTS_ALICE_PWD success:^{ - - // - Alice creates a dehydrated device - [self.dehydrationService dehydrateDeviceWithMatrixRestClient:aliceSession.matrixRestClient crossSigning:aliceSession.legacyCrypto.legacyCrossSigning dehydrationKey:self.dehydrationKey success:^(NSString *deviceId) { - dispatch_async(dispatch_get_main_queue(), ^{ - // - Alice logs out and logs on - [self.matrixSDKTestsData loginUserOnANewDevice:self credentials:nil withPassword:MXTESTS_ALICE_PWD sessionToLogout:aliceSession newSessionStore:nil startNewSession:NO e2e:YES onComplete:^(MXSession *aliceSession2) { - - MXRestClient *aliceRestClient = aliceSession2.matrixRestClient; - - MXSession *aliceSession3 = [[MXSession alloc] initWithMatrixRestClient:aliceRestClient]; - [self.matrixSDKTestsData retain:aliceSession3]; - - [aliceSession2 close]; - - // - Alice rehydrates the new session with the dehydrated device - [self.dehydrationService rehydrateDeviceWithMatrixRestClient:aliceSession3.matrixRestClient dehydrationKey:self.dehydrationKey success:^(NSString *rehydratedDeviceId) { - if (!rehydratedDeviceId) - { - XCTFail(@"device rehydration shouldn't be canceled"); - [expectation fulfill]; - return; - } - aliceSession3.credentials.deviceId = rehydratedDeviceId; - - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - - // - And starts her new session with e2e enabled - [aliceSession3 setStore:[MXMemoryStore new] success:^{ - - [aliceSession3 start:^{ - MXRoom *roomFromBobPOV = [bobSession roomWithRoomId:roomId]; - MXRoom *roomFromAlice3POV = [aliceSession3 roomWithRoomId:roomId]; - - XCTAssertNotNil(roomFromBobPOV, @"roomFromBobPOV shouldn't be nil"); - - if (!roomFromAlice3POV) - { - XCTFail(@"Not able to get room with Alice's session"); - [expectation fulfill]; - return; - } - - NSString *messageFromBob = @"Hello I'm Bob!"; - - [roomFromAlice3POV liveTimeline:^(id liveTimeline) { - // -> Alice must be able to receive and decrypt the message sent by Bob - [liveTimeline listenToEventsOfTypes:@[kMXEventTypeStringRoomMessage, kMXEventTypeStringRoomEncrypted] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) { - - XCTAssertEqual(0, [self checkEncryptedEvent:event roomId:roomId clearMessage:messageFromBob senderSession:bobSession]); - - [expectation fulfill]; - - }]; - }]; - - // - Bob sends a message - [roomFromBobPOV sendTextMessage:messageFromBob threadId:nil success:nil failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }]; - }); - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Failed setting up cross-signing with error: %@", error); - }]; - }]; - return; -} - -// Check that others can see a dehydrated device -// - Alice and Bob are in an e2e room -// - Bob creates a dehydrated device and logs out -// - Alice sends a message -// - Bob logs in on a new device -// - Bob rehydrates the new session with the dehydrated device -// - And starts their new session with e2e enabled -// -> Bob must be able to decrypt the message sent by Alice --(void)testReceiveMessageWhileBeingSignedOffWithDeviceRehydration -{ - // - Alice and Bob are in an e2e room - [self.matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES warnOnUnknowDevices:NO readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [bobSession.crypto.crossSigning setupWithPassword:MXTESTS_BOB_PWD success:^{ - MXCredentials *bobCredentials = bobSession.credentials; - - // - Bob creates a dehydrated device and logs out - [self.dehydrationService dehydrateDeviceWithMatrixRestClient:bobSession.matrixRestClient crossSigning:bobSession.legacyCrypto.legacyCrossSigning dehydrationKey:self.dehydrationKey success:^(NSString *bobDehydratedDeviceId) { - dispatch_async(dispatch_get_main_queue(), ^{ - [bobSession logout:^{ - [bobSession close]; - - // - Alice sends a message - NSString *message = @"Hello I'm Alice!"; - MXRoom *roomFromAlicePOV = [aliceSession roomWithRoomId:roomId]; - [roomFromAlicePOV sendTextMessage:message threadId:nil success:^(NSString *eventId) { - - // - Bob logs in on a new device - [self.matrixSDKTestsData loginUserOnANewDevice:self credentials:bobCredentials withPassword:MXTESTS_BOB_PWD sessionToLogout:nil newSessionStore:nil startNewSession:NO e2e:YES onComplete:^(MXSession *bobSession2) { - - // - Bob rehydrates the new session with the dehydrated device - [self.dehydrationService rehydrateDeviceWithMatrixRestClient:bobSession2.matrixRestClient dehydrationKey:self.dehydrationKey success:^(NSString *deviceId) { - if (!deviceId) - { - XCTFail(@"device rehydration shouldn't be canceled"); - [expectation fulfill]; - return; - } - bobSession2.credentials.deviceId = deviceId; - - // - And starts their new session with e2e enabled - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [bobSession2 start:^{ - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; - - // -> Bob must be able to decrypt the message sent by Alice - [bobSession2 eventWithEventId:eventId inRoom:roomId success:^(MXEvent *event) { - - XCTAssertEqual(event.wireEventType, MXEventTypeRoomEncrypted); - XCTAssertEqual(event.eventType, MXEventTypeRoomMessage); - XCTAssertEqualObjects(event.content[kMXMessageBodyKey], message); - XCTAssertNil(event.decryptionError); - - [expectation fulfill]; - - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - }); - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Failed setting up cross-signing with error: %@", error); - }]; - }]; -} - -// Test for pickling / unpinling OLM acount -// - create a new OLM Acount -// - pickle the OLM account -// - unpickle the pickled account -// -> identity keys must be the same --(void)testDataPickling -{ - // - create a new OLM Acount - OLMAccount *account = [[OLMAccount alloc] initNewAccount]; - NSDictionary *e2eKeys = [account identityKeys]; - - [account generateOneTimeKeys:50]; - NSDictionary *oneTimeKeys = [account oneTimeKeys]; - - [account generateFallbackKey]; - NSDictionary *fallbackKey = [account fallbackKey]; - - // - pickle the OLM account - NSData *key = [@"6fXK17pQFUrFqOnxt3wrqz8RHkQUT9vQ" dataUsingEncoding:NSUTF8StringEncoding]; - NSError *error = nil; - NSString *serializedAccount = [account serializeDataWithKey:key error:&error]; - - XCTAssertNil(error, "serializeDataWithKey failed due to error %@", error); - - // - unpickle the pickled account - OLMAccount *deserializedAccount = [[OLMAccount alloc] initWithSerializedData:serializedAccount key:key error:&error]; - NSDictionary *deserializedE2eKeys = [deserializedAccount identityKeys]; - NSDictionary *deserializedOneTimeKeys = [deserializedAccount oneTimeKeys]; - NSDictionary *deserializedFallbackKey = [deserializedAccount fallbackKey]; - - // -> identity keys must be the same - XCTAssertNil(error, "initWithSerializedData failed due to error %@", error); - XCTAssert([e2eKeys[@"ed25519"] isEqual:deserializedE2eKeys[@"ed25519"]], @"wrong deserialized ed25519 key %@ != %@", e2eKeys[@"ed25519"], deserializedE2eKeys[@"ed25519"]); - XCTAssert([e2eKeys[@"curve25519"] isEqual:deserializedE2eKeys[@"curve25519"]], @"wrong deserialized curve25519 key %@ != %@", e2eKeys[@"curve25519"], deserializedE2eKeys[@"curve25519"]); - - XCTAssert([oneTimeKeys isEqualToDictionary:deserializedOneTimeKeys]); - XCTAssert([fallbackKey isEqualToDictionary:deserializedFallbackKey]); -} - -#pragma mark - Private methods - -- (NSUInteger)checkEncryptedEvent:(MXEvent*)event roomId:(NSString*)roomId clearMessage:(NSString*)clearMessage senderSession:(MXSession*)senderSession -{ - NSUInteger failureCount = self.testRun.failureCount; - - // Check raw event (encrypted) data as sent by the hs - XCTAssertEqual(event.wireEventType, MXEventTypeRoomEncrypted); - XCTAssertNil(event.wireContent[kMXMessageBodyKey], @"No body field in an encrypted content"); - XCTAssertEqualObjects(event.wireContent[@"algorithm"], kMXCryptoMegolmAlgorithm); - XCTAssertNotNil(event.wireContent[@"ciphertext"]); - XCTAssertNotNil(event.wireContent[@"session_id"]); - XCTAssertNotNil(event.wireContent[@"sender_key"]); - XCTAssertEqualObjects(event.wireContent[@"device_id"], senderSession.legacyCrypto.store.deviceId); - - // Check decrypted data - XCTAssert(event.eventId); - XCTAssertEqualObjects(event.roomId, roomId); - XCTAssertEqual(event.eventType, MXEventTypeRoomMessage); - XCTAssertLessThan(event.age, 10000); - XCTAssertEqualObjects(event.content[kMXMessageBodyKey], clearMessage); - XCTAssertEqualObjects(event.sender, senderSession.myUser.userId); - XCTAssertNil(event.decryptionError); - - // Return the number of failures in this method - return self.testRun.failureCount - failureCount; -} - -@end - -#pragma clang diagnostic pop - diff --git a/MatrixSDKTests/MXPollAggregatorTests.swift b/MatrixSDKTests/MXPollAggregatorTests.swift index 9862243eda..0f7f0825f4 100644 --- a/MatrixSDKTests/MXPollAggregatorTests.swift +++ b/MatrixSDKTests/MXPollAggregatorTests.swift @@ -40,12 +40,12 @@ class MXPollAggregatorTest: XCTestCase { func testAggregations() { self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { pollAggregator in - XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2) - XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0) + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 2) + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0) expectation.fulfill() }) - self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) + self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) let dispatchGroup = DispatchGroup() @@ -74,14 +74,14 @@ class MXPollAggregatorTest: XCTestCase { func testSessionPausing() { self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in let delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in - XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2) - XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 0) + XCTAssertEqual(aggregator.poll?.answerOptions.first!.count, 2) + XCTAssertEqual(aggregator.poll?.answerOptions.last!.count, 0) }) - self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) + self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) - XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice - XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0) + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 1) // One from Alice + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0) bobSession.pause() @@ -99,16 +99,16 @@ class MXPollAggregatorTest: XCTestCase { func testGappySync() { self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in - self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) + self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in - XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2) // One from Bob and one from Alice - XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 1) // One from Alice + XCTAssertEqual(aggregator.poll?.answerOptions.first!.count, 2) // One from Bob and one from Alice + XCTAssertEqual(aggregator.poll?.answerOptions.last!.count, 1) // One from Alice expectation.fulfill() }) - XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice - XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0) + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 1) // One from Alice + XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0) bobSession.pause() @@ -135,7 +135,7 @@ class MXPollAggregatorTest: XCTestCase { func testEditing() { self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in - self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) + self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId) self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in defer { @@ -144,9 +144,9 @@ class MXPollAggregatorTest: XCTestCase { guard self.isFirstDelegateUpdate else { return } - XCTAssertEqual(aggregator.poll.text, "Some other question") - XCTAssertEqual(aggregator.poll.answerOptions.count, 2) - XCTAssertTrue(aggregator.poll.hasBeenEdited) + XCTAssertEqual(aggregator.poll?.text, "Some other question") + XCTAssertEqual(aggregator.poll?.answerOptions.count, 2) + XCTAssertEqual(aggregator.poll?.hasBeenEdited, true) expectation.fulfill() }) diff --git a/MatrixSDKTests/MXToolsUnitTests.m b/MatrixSDKTests/MXToolsUnitTests.m index 4e15a4e109..efcf636df4 100644 --- a/MatrixSDKTests/MXToolsUnitTests.m +++ b/MatrixSDKTests/MXToolsUnitTests.m @@ -68,6 +68,58 @@ - (void)testMatrixIdentifiers XCTAssertTrue([MXTools isMatrixGroupIdentifier:@"+matrix:matrix.org"]); } +- (void)testEmailAddresses +{ + XCTAssertTrue([MXTools isEmailAddress:@"alice@matrix.org"]); + XCTAssertTrue([MXTools isEmailAddress:@"alice@matrix"]); + XCTAssertTrue([MXTools isEmailAddress:@"al-i_ce@matrix"]); + XCTAssertTrue([MXTools isEmailAddress:@"al+ice@matrix.org"]); + XCTAssertTrue([MXTools isEmailAddress:@"al=ice@matrix.org"]); + XCTAssertTrue([MXTools isEmailAddress:@"*@example.net"]); + XCTAssertTrue([MXTools isEmailAddress:@"fred&barny@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"---@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"foo-bar@example.net"]); + XCTAssertTrue([MXTools isEmailAddress:@"mailbox.sub1.sub2@this-domain"]); + XCTAssertTrue([MXTools isEmailAddress:@"prettyandsimple@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"very.common@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"disposable.style.email.with+symbol@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"other.email-with-dash@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"x@example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"example-indeed@strange-example.com"]); + XCTAssertTrue([MXTools isEmailAddress:@"admin@mailserver1"]); + XCTAssertTrue([MXTools isEmailAddress:@"#!$%&'*+-/=?^_`{}|~@example.org"]); + XCTAssertTrue([MXTools isEmailAddress:@"example@localhost"]); + XCTAssertTrue([MXTools isEmailAddress:@"example@s.solutions"]); + XCTAssertTrue([MXTools isEmailAddress:@"user@localserver"]); + XCTAssertTrue([MXTools isEmailAddress:@"user@tt"]); + XCTAssertTrue([MXTools isEmailAddress:@"xn--80ahgue5b@xn--p-8sbkgc5ag7bhce.xn--ba-lmcq"]); + XCTAssertTrue([MXTools isEmailAddress:@"nothing@xn--fken-gra.no"]); + + XCTAssertFalse([MXTools isEmailAddress:@"alice.matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"al ice@matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"al(ice@matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"alice@"]); + XCTAssertFalse([MXTools isEmailAddress:@"al\nice@matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"al@ice@matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"al@ice@.matrix.org"]); + XCTAssertFalse([MXTools isEmailAddress:@"Just a string"]); + XCTAssertFalse([MXTools isEmailAddress:@"string"]); + XCTAssertFalse([MXTools isEmailAddress:@"me@"]); + XCTAssertFalse([MXTools isEmailAddress:@"@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"me.@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@".me@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"me@example..com"]); + XCTAssertFalse([MXTools isEmailAddress:@"me\\@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"Abc.example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"A@b@c@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"a\"b(c)d,e:f;gi[j\\k]l@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"just\"not\"right@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"this is\"not\\allowed@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"this\\ still\\\"not\\\\allowed@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"john..doe@example.com"]); + XCTAssertFalse([MXTools isEmailAddress:@"john.doe@example..com"]); +} + #pragma mark - Strings encoding diff --git a/MatrixSDKTests/MatrixSDKTestsE2EData.m b/MatrixSDKTests/MatrixSDKTestsE2EData.m index a93e8479dd..c6e6cf3e33 100644 --- a/MatrixSDKTests/MatrixSDKTestsE2EData.m +++ b/MatrixSDKTests/MatrixSDKTestsE2EData.m @@ -63,12 +63,14 @@ - (void)doE2ETestWithBobAndAlice:(XCTestCase*)testCase readyToTest:(void (^)(MXSession *bobSession, MXSession *aliceSession, XCTestExpectation *expectation))readyToTest { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; [matrixSDKTestsData doMXSessionTestWithBob:testCase readyToTest:^(MXSession *bobSession, XCTestExpectation *expectation) { [matrixSDKTestsData doMXSessionTestWithAlice:nil readyToTest:^(MXSession *aliceSession, XCTestExpectation *expectation2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; readyToTest(bobSession, aliceSession, expectation); @@ -85,11 +87,13 @@ - (void)doE2ETestWithAliceInARoom:(XCTestCase*)testCase - (void)doE2ETestWithAliceInARoom:(XCTestCase *)testCase andStore:(id)store readyToTest:(void (^)(MXSession *, NSString *, XCTestExpectation *))readyToTest { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; [matrixSDKTestsData doMXSessionTestWithAlice:testCase andStore:store readyToTest:^(MXSession *aliceSession, XCTestExpectation *expectation) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; [aliceSession createRoom:nil visibility:kMXRoomDirectoryVisibilityPrivate roomAlias:nil topic:nil success:^(MXRoom *room) { @@ -128,10 +132,15 @@ - (void)doE2ETestWithAliceAndBobInARoom:(XCTestCase*)testCase MXRoom *room = [aliceSession roomWithRoomId:roomId]; [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = cryptedBob; + if (cryptedBob) + { + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; + } [matrixSDKTestsData doMXSessionTestWithBob:nil andStore:bobStore readyToTest:^(MXSession *bobSession, XCTestExpectation *expectation2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; aliceSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; bobSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; @@ -180,10 +189,15 @@ - (void)doE2ETestWithAliceByInvitingBobInARoom:(XCTestCase*)testCase MXRoom *room = [aliceSession roomWithRoomId:roomId]; [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = cryptedBob; + if (cryptedBob) + { + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; + } [matrixSDKTestsData doMXSessionTestWithBob:nil andStore:bobStore readyToTest:^(MXSession *bobSession, XCTestExpectation *expectation2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; aliceSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; bobSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; @@ -256,12 +270,17 @@ - (void)doE2ETestWithAliceAndBobAndSamInARoom:(XCTestCase*)testCase MXRoom *room = [aliceSession roomWithRoomId:roomId]; [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = cryptedSam; + if (cryptedSam) + { + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; + } // Ugly hack: Create a bob from another MatrixSDKTestsData instance and call him Sam... MatrixSDKTestsData *matrixSDKTestsData2 = [[MatrixSDKTestsData alloc] init]; [matrixSDKTestsData2 doMXSessionTestWithBob:nil readyToTest:^(MXSession *samSession, XCTestExpectation *expectation2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; aliceSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; bobSession.legacyCrypto.warnOnUnknowDevices = warnOnUnknowDevices; @@ -309,6 +328,7 @@ - (void)loginUserOnANewDevice:(XCTestCase*)testCase onComplete:(void (^)(MXSession *newSession))onComplete { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; + MXKeyProvider.sharedInstance.delegate = [[MXKeyProviderStub alloc] init]; MXRestClient *mxRestClient = [[MXRestClient alloc] initWithHomeServer:credentials.homeServer andOnUnrecognizedCertificateBlock:nil]; @@ -327,6 +347,7 @@ - (void)loginUserOnANewDevice:(XCTestCase*)testCase MXStrongifyAndReturnIfNil(newSession); [newSession start:^{ [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; + MXKeyProvider.sharedInstance.delegate = nil; onComplete(newSession); diff --git a/MatrixSDKTests/TestPlans/AllWorkingTests.xctestplan b/MatrixSDKTests/TestPlans/AllWorkingTests.xctestplan index fb12ca99dc..711f37fbce 100644 --- a/MatrixSDKTests/TestPlans/AllWorkingTests.xctestplan +++ b/MatrixSDKTests/TestPlans/AllWorkingTests.xctestplan @@ -17,6 +17,7 @@ "DirectRoomTests\/testDirectRoomsAfterInitialSync", "DirectRoomTests\/testDirectRoomsRaceConditions", "DirectRoomTests\/testSummaryAfterInitialSyncAndStorage", + "MXAes256KeyBackupTests", "MXAggregatedEditsTests\/testEditSendAndReceive", "MXAggregatedEditsTests\/testEditSendAndReceiveInE2ERoom", "MXAggregatedEditsTests\/testEditServerSide", @@ -26,7 +27,10 @@ "MXAggregatedEditsTests\/testFormattedEditSendAndReceive", "MXAggregatedEditsTests\/testFormattedEditServerSide", "MXAggregatedEditsUnitTests", + "MXAggregatedReactionTests", + "MXAggregatedReactionTests\/testAggregatedReactionServerSide", "MXAggregatedReactionTests\/testAggregationsFromInitialSync", + "MXAggregatedReactionTests\/testReactionsOnPermalinkFromAGappyInitialSync", "MXAggregatedReactionTests\/testReactionsWhenPaginatingFromAGappyInitialSync", "MXAggregatedReactionTests\/testReactionsWhenPaginatingFromAGappySync", "MXAggregatedReactionTests\/testUnreactAfterInitialSync", @@ -36,36 +40,84 @@ "MXAggregatedReferenceUnitTests", "MXAsyncTaskQueueUnitTests", "MXAuthenticationSessionUnitTests", + "MXAutoDiscoveryTests\/testAutoDiscoveryInvalidIdendityServer", "MXAutoDiscoveryTests\/testAutoDiscoveryNotJSON", "MXAutoDiscoveryTests\/testAutoDiscoverySuccessful", "MXAutoDiscoveryTests\/testAutoDiscoverySuccessfulWithNoContentType", + "MXBackgroundSyncServiceTests", "MXBackgroundSyncServiceTests\/testStoreWithGappyAndOutdatedSync()", "MXBackgroundTaskUnitTests", + "MXBaseKeyBackupTests", "MXBeaconInfoUnitTests", "MXCredentialsUnitTests", "MXCrossSigningTests", "MXCrossSigningVerificationTests", - "MXCrossSigningVerificationTests\/testVerificationByDMFullFlow", - "MXCrossSigningVerificationTests\/testVerifyingAnotherUserQRCodeVerificationFullFlow", "MXCryptoBackupTests", "MXCryptoKeyVerificationTests", - "MXCryptoKeyVerificationTests\/testVerificationByDMFullFlow", - "MXCryptoKeyVerificationTests\/testVerificationByDMWithAUserWith2Devices", - "MXCryptoKeyVerificationTests\/testVerificationByDMWithAliceWith2Devices", + "MXCryptoMigrationTests", "MXCryptoRecoveryServiceTests", "MXCryptoRequestsUnitTests", - "MXCryptoSecretShareTests\/testSecretRequestCancellation", - "MXCryptoSecretStorageTests\/testDeleteSecret", + "MXCryptoSecretShareTests", + "MXCryptoSecretStorageTests", "MXCryptoShareTests", - "MXCryptoTests", + "MXCryptoTests\/testAliceAndBlockedBob", + "MXCryptoTests\/testAliceAndBobInACryptedRoom", + "MXCryptoTests\/testAliceAndBobInACryptedRoom2", + "MXCryptoTests\/testAliceAndBobInACryptedRoomBackPaginationFromHomeServer", + "MXCryptoTests\/testAliceAndBobInACryptedRoomBackPaginationFromMemoryStore", + "MXCryptoTests\/testAliceAndBobInACryptedRoomFromInitialSync", + "MXCryptoTests\/testAliceAndBobWithNewDevice", + "MXCryptoTests\/testAliceAndNotCryptedBobInACryptedRoom", + "MXCryptoTests\/testAliceDecryptOldMessageWithANewDeviceInACryptedRoom", + "MXCryptoTests\/testAliceInACryptedRoom", + "MXCryptoTests\/testAliceInACryptedRoomAfterInitialSync", + "MXCryptoTests\/testAliceInACryptedRoomWithoutEncryption", + "MXCryptoTests\/testAliceWithNewDeviceAndBob", + "MXCryptoTests\/testAliceWithNewDeviceAndBobWithNewDevice", + "MXCryptoTests\/testBadSummaryIsEncryptedState", + "MXCryptoTests\/testBlackListUnverifiedDevices", + "MXCryptoTests\/testCryptoNoDeviceId", + "MXCryptoTests\/testCryptoPersistenceInStore", + "MXCryptoTests\/testDeviceInvalidationWhileSending", + "MXCryptoTests\/testDiscardAndRestoreOlmOutboundKey", + "MXCryptoTests\/testDownloadKeysForUserWithNoDevice", + "MXCryptoTests\/testDownloadKeysWithUnreachableHS", + "MXCryptoTests\/testEnableEncryptionAfterNonCryptedMessages", + "MXCryptoTests\/testEncryptionAlgorithmChange", + "MXCryptoTests\/testEnsureSingleOlmSession", + "MXCryptoTests\/testExportImportRoomKeysWithPassword", + "MXCryptoTests\/testFallbackKeySignatures", + "MXCryptoTests\/testFirstMessageSentWhileSessionWasPaused", + "MXCryptoTests\/testHasKeysToDecryptEvent", + "MXCryptoTests\/testImportRoomKeysWithWrongPassword", + "MXCryptoTests\/testIncomingRoomKeyRequest", + "MXCryptoTests\/testInvitedMemberInACryptedRoom", + "MXCryptoTests\/testInvitedMemberInACryptedRoom2", + "MXCryptoTests\/testIsRoomSharingHistory", + "MXCryptoTests\/testLateRoomKey", + "MXCryptoTests\/testLeftAndJoinedBob", + "MXCryptoTests\/testLeftBobAndAliceWithNewDevice", + "MXCryptoTests\/testMXDeviceListDidUpdateUsersDevicesNotification", + "MXCryptoTests\/testMXSessionEventWithEventId", + "MXCryptoTests\/testMultipleDownloadKeys", + "MXCryptoTests\/testOlmSessionUnwedging", + "MXCryptoTests\/testReplayAttack", + "MXCryptoTests\/testReplayAttackForEventEdits", + "MXCryptoTests\/testRestoreOlmOutboundKey", + "MXCryptoTests\/testRoomIsEncrypted", + "MXCryptoTests\/testRoomKeyReshare", + "MXCryptoTests\/testSendReplyToTextMessage", + "MXDehydrationTests", "MXErrorUnitTests", "MXEventAnnotationUnitTests", "MXEventReferenceUnitTests", "MXEventScanStoreUnitTests", "MXFilterTests\/testFilterAPI", "MXFilterTests\/testFilterCache", + "MXFilterTests\/testUnsupportedSyncFilter", "MXFilterUnitTests", "MXGeoURIComponentsUnitTests", + "MXHTTPClientTests", "MXHTTPClientTests\/testMainThread", "MXJSONModelTests\/testModelFromJSON", "MXJSONModelTests\/testModelsFromJSON", @@ -87,14 +139,30 @@ "MXPollRelationTests\/testBobAndAliceAnswer", "MXPushRuleUnitTests", "MXQRCodeDataUnitTests", + "MXReceiptDataIntegrationTests", + "MXReceiptDataIntegrationTests\/testAcknowledgeMessageInMainTimeline()", + "MXReceiptDataIntegrationTests\/testAcknowledgeMessageInThread()", + "MXReceiptDataIntegrationTests\/testReadReceiptsStorageInThread()", "MXReplyEventParserUnitTests", "MXResponseUnitTests", "MXRestClientExtensionsTests", "MXRestClientNoAuthAPITests", + "MXRestClientTests", + "MXRestClientTests\/testAddAndRemoveTag", + "MXRestClientTests\/testBanUserInRoom", + "MXRestClientTests\/testClaimOneTimeKeysForUsersDevices", + "MXRestClientTests\/testClose", + "MXRestClientTests\/testContextOfEvent", "MXRestClientTests\/testJoinRoomWithRoomAlias", + "MXRoomAliasAvailabilityCheckerResultTests", + "MXRoomAliasAvailabilityCheckerResultTests\/testAliasAvailable()", "MXRoomListDataManagerTests\/testNewRoomInvite()", "MXRoomListDataManagerTests\/testRoomLeave()", + "MXRoomListDataManagerTests\/testRoomUpdateWhenReceivingEncryptedEvent()", "MXRoomListDataManagerTests\/testRoomUpdateWhenReceivingEvent()", + "MXRoomListDataManagerTests\/testRoomUpdateWithLateRoomKeyFix()", + "MXRoomListDataManagerTests\/testRoomUpdateWithLateRoomKeyFixAfterBobRestart()", + "MXRoomListDataManagerTests\/testRoomUpdateWithUTD()", "MXRoomStateTests\/testDeallocation", "MXRoomStateTests\/testInviteByOtherInInitialSync", "MXRoomStateTests\/testInviteByOtherInLive", @@ -109,8 +177,10 @@ "MXSelfSignedHomeserverTests\/testTrustedCertificate", "MXSessionTests", "MXSharedHistoryKeyManagerUnitTests", + "MXSpaceChildContentTests\/testCreateSpaceCheckVisibilityOfPublicRoom()", "MXSpaceChildContentTests\/testUpdateChildSuggestion()", "MXSpaceChildContentTests\/testUpgradeSpaceChild()", + "MXSpaceServiceTest\/testCreateSpace()", "MXStoreFileStoreTests", "MXStoreMemoryStoreTests", "MXStoreNoStoreTests\/testMXNoStoreSeveralPaginateBacks", diff --git a/MatrixSDKTests/TestPlans/CryptoTests.xctestplan b/MatrixSDKTests/TestPlans/CryptoTests.xctestplan deleted file mode 100644 index 4c943befc0..0000000000 --- a/MatrixSDKTests/TestPlans/CryptoTests.xctestplan +++ /dev/null @@ -1,52 +0,0 @@ -{ - "configurations" : [ - { - "id" : "1FA4678B-FC03-4484-997A-D8629931F24B", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - "codeCoverage" : { - "targets" : [ - { - "containerPath" : "container:MatrixSDK.xcodeproj", - "identifier" : "B14EF1C72397E90400758AF0", - "name" : "MatrixSDK-macOS" - } - ] - }, - "targetForVariableExpansion" : { - "containerPath" : "container:MatrixSDK.xcodeproj", - "identifier" : "B14EF1C72397E90400758AF0", - "name" : "MatrixSDK-macOS" - }, - "uiTestingScreenshotsLifetime" : "keepNever", - "userAttachmentLifetime" : "keepNever" - }, - "testTargets" : [ - { - "selectedTests" : [ - "MXAes256KeyBackupTests", - "MXCrossSigningTests", - "MXCrossSigningVerificationTests", - "MXCryptoKeyVerificationTests", - "MXCryptoMigrationV2Tests", - "MXCryptoSecretStorageTests", - "MXCryptoShareTests", - "MXCryptoTests", - "MXCryptoV2FactoryTests", - "MXCurve25519KeyBackupTests", - "MXMegolmEncryptionTests" - ], - "target" : { - "containerPath" : "container:MatrixSDK.xcodeproj", - "identifier" : "B1E09A0D2397FA950057C069", - "name" : "MatrixSDKTests-macOS" - } - } - ], - "version" : 1 -} diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index 1ebc14fb9b..730bc6d142 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -47,7 +47,9 @@ "MXCryptoKeyBackupEngineUnitTests", "MXCryptoMachineUnitTests", "MXCryptoMigrationStoreUnitTests", + "MXCryptoMigrationV2UnitTests", "MXCryptoRequestsUnitTests", + "MXCryptoV2FactoryUnitTests", "MXDeviceInfoSourceUnitTests", "MXDeviceInfoUnitTests", "MXDeviceListOperationsPoolUnitTests", diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index 392638cb35..4435fd6fbb 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -57,7 +57,9 @@ "MXCryptoKeyBackupEngineUnitTests", "MXCryptoMachineUnitTests", "MXCryptoMigrationStoreUnitTests", + "MXCryptoMigrationV2UnitTests", "MXCryptoRequestsUnitTests", + "MXCryptoV2FactoryUnitTests", "MXDeviceInfoSourceUnitTests", "MXDeviceInfoUnitTests", "MXDeviceListOperationsPoolUnitTests", diff --git a/Podfile b/Podfile index 51908e1787..7fadd78933 100644 --- a/Podfile +++ b/Podfile @@ -15,7 +15,7 @@ abstract_target 'MatrixSDK' do pod 'Realm', '10.27.0' pod 'libbase58', '~> 0.1.4' - pod 'MatrixSDKCrypto', "0.3.4", :inhibit_warnings => true + pod 'MatrixSDKCrypto', "0.3.13", :inhibit_warnings => true target 'MatrixSDK-iOS' do platform :ios, '11.0' diff --git a/Podfile.lock b/Podfile.lock index 7844be65da..35bb330fe3 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -16,7 +16,7 @@ PODS: - AFNetworking/NSURLSession - GZIP (1.3.0) - libbase58 (0.1.4) - - MatrixSDKCrypto (0.3.4) + - MatrixSDKCrypto (0.3.13) - OHHTTPStubs (9.1.0): - OHHTTPStubs/Default (= 9.1.0) - OHHTTPStubs/Core (9.1.0) @@ -43,7 +43,7 @@ DEPENDENCIES: - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - - MatrixSDKCrypto (= 0.3.4) + - MatrixSDKCrypto (= 0.3.13) - OHHTTPStubs (~> 9.1.0) - OLMKit (~> 3.2.5) - Realm (= 10.27.0) @@ -62,11 +62,11 @@ SPEC CHECKSUMS: AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3 libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd - MatrixSDKCrypto: ac805c22c24f79f349cdbfa065855c73a4c81b51 + MatrixSDKCrypto: bf08b72f2cd015d8749420a2b8b92fc0536bedf4 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 OLMKit: da115f16582e47626616874e20f7bb92222c7a51 Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 -PODFILE CHECKSUM: 21e3d61972284ed62a11d0fbea9b705ba7c36760 +PODFILE CHECKSUM: 7022de81b9c13a3727800ca21d4a4d2bf6b6d1b6 -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a9fdad60b3..c029c05bd3 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -18,7 +18,7 @@ platform :ios do before_all do # Ensure used Xcode version - xcversion(version: "~> 13.2") + xcversion(version: "14.2") end #### Pod ####