From 196004568478e819e07a793d45a4877f9bdb8950 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 7 Nov 2024 21:14:52 -0500 Subject: [PATCH 01/98] [Infra] Update functions workflow to use macOS 15 for Xcode 16 jobs (#14051) --- .github/workflows/functions.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index 226583412e0..49d26b29a5c 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -30,8 +30,11 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] + include: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -116,22 +119,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: From 0006c727859b7691f9d9ec0e2b88a4a79e43f4f6 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 11:38:07 -0500 Subject: [PATCH 02/98] [Infra] Update storage workflow to use macOS 15 for Xcode 16 jobs (#14056) --- .github/workflows/storage.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 4df045aae24..6c4f331dbde 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -25,7 +25,7 @@ jobs: language: [Swift, ObjC] include: - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: ${{ matrix.os }} @@ -96,22 +96,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: @@ -200,8 +200,8 @@ jobs: - os: macos-14 xcode: Xcode_15.3 tests: --skip-tests - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 tests: --test-specs=unit runs-on: ${{ matrix.os }} steps: @@ -224,12 +224,12 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] + os: [macos-14, macos-15] include: - os: macos-14 xcode: Xcode_15.3 - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} needs: pod-lib-lint steps: From f2fa16877768288fa5348cad6e2a96b372fde0e6 Mon Sep 17 00:00:00 2001 From: themiswang Date: Fri, 8 Nov 2024 13:07:19 -0500 Subject: [PATCH 03/98] Change deprecated keyWindow to new API (#14048) --- .../Instrumentation/UIKit/FPRUIViewControllerInstrument.m | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m b/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m index 147b53c516a..1c2226148ca 100644 --- a/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m +++ b/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m @@ -69,15 +69,9 @@ void InstrumentViewDidAppear(FPRUIViewControllerInstrument *instrument, // This has to be called on the main thread and so it's done here instead of in // FPRScreenTraceTracker. - // TODO(#13067): Replace keyWindow usage (deprecated in iOS and unavailable in visionOS). -#if !defined(TARGET_OS_VISION) || !TARGET_OS_VISION -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - if ([((UIViewController *)_self).view isDescendantOfView:FPRSharedApplication().keyWindow]) { -#pragma clang diagnostic pop + if (FPRSharedApplication() && ((UIViewController *)_self).view.window.keyWindow) { [[FPRScreenTraceTracker sharedInstance] viewControllerDidAppear:_self]; } -#endif }]; } From 6b18b14538b976bc9314d3aa33e31465c19f51b9 Mon Sep 17 00:00:00 2001 From: Aashish <112133849+aashishpatil-g@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:31:37 -0800 Subject: [PATCH 04/98] Exempt the Data Connect FriendlyFlix Generated Code from style scripts (#14063) --- scripts/style.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/style.sh b/scripts/style.sh index 01989affed7..ea8172060fe 100755 --- a/scripts/style.sh +++ b/scripts/style.sh @@ -153,6 +153,9 @@ s%^./%% # Generated source \%/Firestore/core/src/util/config.h% d +# Generated Code for Data Connect sample +\%/Examples/FriendlyFlix/app/FriendlyFlixSDK/% d + # Sources pulled in by travis bundler, with and without a leading slash \%^/?vendor/bundle/% d From bec796d8959e7bca6b82e19d693e701505033552 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 17:20:09 -0500 Subject: [PATCH 05/98] [Infra] Update core_extension workflow to use macOS 15 for Xcode 16 (#14059) --- .github/workflows/core_extension.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/core_extension.yml b/.github/workflows/core_extension.yml index b728bbc3bff..ded570c1972 100644 --- a/.github/workflows/core_extension.yml +++ b/.github/workflows/core_extension.yml @@ -20,16 +20,19 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreExtension.podspec --platforms=${{ matrix.target }} From e7650589e560b039346a9cd38109a8c6ec9c314c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 17:22:47 -0500 Subject: [PATCH 06/98] [Infra] Update firebase_app_check workflow to use macOS 15 for Xcode 16 (#14062) --- .github/workflows/firebase_app_check.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/firebase_app_check.yml b/.github/workflows/firebase_app_check.yml index 613146e80fc..87452aecaa4 100644 --- a/.github/workflows/firebase_app_check.yml +++ b/.github/workflows/firebase_app_check.yml @@ -22,9 +22,12 @@ jobs: matrix: podspec: [FirebaseAppCheckInterop.podspec, FirebaseAppCheck.podspec] target: [ios, tvos, macos --skip-tests, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 @@ -33,7 +36,7 @@ jobs: - name: Configure test keychain run: scripts/configure_test_keychain.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: FirebaseAppCheck run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} From 0aca0bf9110458ae78a0c083c6dbc14a67588a31 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 17:39:54 -0500 Subject: [PATCH 07/98] [Infra] Update database workflow to use macOS 15 for Xcode 16 (#14060) --- .github/workflows/database.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 7570be9c9bd..5b390d0184a 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -26,16 +26,19 @@ jobs: strategy: matrix: target: [ios, tvos, macos --skip-tests, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseDatabase.podspec --test-specs=unit --platforms=${{ matrix.target }} @@ -96,22 +99,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: From 4e5fbe892e9e74c68725e54fdde5c28dc0fb60ba Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 17:58:50 -0500 Subject: [PATCH 08/98] [Infra] Update mlmodeldownloader workflow to use macOS 15 for Xcode 16 (#14066) --- .github/workflows/mlmodeldownloader.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/mlmodeldownloader.yml b/.github/workflows/mlmodeldownloader.yml index 81da1ab1a83..39d4ba45558 100644 --- a/.github/workflows/mlmodeldownloader.yml +++ b/.github/workflows/mlmodeldownloader.yml @@ -22,9 +22,12 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 @@ -38,7 +41,7 @@ jobs: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/MLModelDownloader/GoogleService-Info.plist.gpg \ FirebaseMLModelDownloader/Tests/Integration/Resources/GoogleService-Info.plist "$plist_secret" - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseMLModelDownloader.podspec --platforms=${{ matrix.target }}) @@ -102,22 +105,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: From 2efd3397d21e6347cd99b90091336cb6ae8be603 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 18:09:53 -0500 Subject: [PATCH 09/98] [Infra] Fix missing Xcode 15 runs in `functions` and `storage` workflows (#14065) --- .github/workflows/functions.yml | 6 +++--- .github/workflows/storage.yml | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index 49d26b29a5c..5b7dc6c26cc 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -30,17 +30,17 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - include: + build-env: - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh # The integration tests are flaky on Xcode 15 so only run the unit tests. The integration tests still run with SPM. diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 6c4f331dbde..220f98b5741 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -195,15 +195,14 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - include: + build-env: - os: macos-14 xcode: Xcode_15.3 tests: --skip-tests - os: macos-15 xcode: Xcode_16.1 tests: --test-specs=unit - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 @@ -212,10 +211,10 @@ jobs: - name: Xcodes run: ls -l /Applications/Xcode* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: | - scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseStorage.podspec ${{ matrix.tests }} \ + scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseStorage.podspec ${{ matrix.build-env.tests }} \ --platforms=${{ matrix.target }} storage-cron-only: @@ -224,13 +223,12 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14, macos-15] - include: + build-env: - os: macos-14 xcode: Xcode_15.3 - os: macos-15 xcode: Xcode_16.1 - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} needs: pod-lib-lint steps: - uses: actions/checkout@v4 @@ -238,6 +236,6 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: PodLibLint Storage Cron run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseStorage.podspec --platforms=${{ matrix.target }} --use-static-frameworks --skip-tests From b2a7683a9204b969a30f062b373bc96f1168e266 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 8 Nov 2024 15:51:19 -0800 Subject: [PATCH 10/98] Add Data Connect to Feature Request template (#14064) --- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index 77723218db5..d684c25d5bd 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -54,6 +54,7 @@ body: - Authentication - Crashlytics - Database + - Data Connect - DynamicLinks - Firestore - Functions From a31400dbac346ed5ef31291798429a8c5a1f16fa Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:43:01 -0500 Subject: [PATCH 11/98] [Auth] Restore User decoding to pre-11 behavior (#14069) --- FirebaseAuth/CHANGELOG.md | 5 +++++ FirebaseAuth/Sources/Swift/User/User.swift | 18 +++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index d5e3b31c3ba..ad38ada6e4b 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,8 @@ +# Unreleased +- [fixed] Restore pre-Firebase 11 decoding behavior to prevent users getting + logged out when upgrading from Firebase 8.10.0 or earlier to Firebase 11. + (#14011) + # 11.4.0 - [fixed] Restore Firebase 10 behavior by ignoring `nil` display names used during multi factor enrollment. (#13856) diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index 94d1c13dd0a..08bf6762414 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -1704,11 +1704,6 @@ extension User: NSSecureCoding {} public required init?(coder: NSCoder) { guard let userID = coder.decodeObject(of: NSString.self, forKey: kUserIDCodingKey) as? String, - let apiKey = coder.decodeObject(of: NSString.self, forKey: kAPIKeyCodingKey) as? String, - let appID = coder.decodeObject( - of: NSString.self, - forKey: kFirebaseAppIDCodingKey - ) as? String, let tokenService = coder.decodeObject(of: SecureTokenService.self, forKey: kTokenServiceCodingKey) else { return nil @@ -1746,8 +1741,17 @@ extension User: NSSecureCoding {} self.phoneNumber = phoneNumber self.metadata = metadata ?? UserMetadata(withCreationDate: nil, lastSignInDate: nil) self.tenantID = tenantID - // The `heartbeatLogger` and `appCheck` will be set later via a property update. - requestConfiguration = AuthRequestConfiguration(apiKey: apiKey, appID: appID) + + // Note, in practice, the caller will set the `auth` property of this user + // instance which will as a side-effect overwrite the request configuration. + // The assignment here is a best-effort placeholder. + let apiKey = coder.decodeObject(of: NSString.self, forKey: kAPIKeyCodingKey) as? String + let appID = coder.decodeObject( + of: NSString.self, + forKey: kFirebaseAppIDCodingKey + ) as? String + requestConfiguration = AuthRequestConfiguration(apiKey: apiKey ?? "", appID: appID ?? "") + userProfileUpdate = UserProfileUpdate() #if os(iOS) self.multiFactor = multiFactor ?? MultiFactor() From a89dd313997f0d41b3691a218a5197dbc8db8558 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 19:51:42 -0500 Subject: [PATCH 12/98] [Infra] Update performance workflow to use macOS 15 for Xcode 16 (#14068) --- .github/workflows/performance.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 67a89aef2ae..af24594c944 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -55,16 +55,19 @@ jobs: strategy: matrix: target: [ios, tvos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebasePerformance.podspec --skip-tests --platforms=${{ matrix.target }} @@ -155,10 +158,10 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS runs-on: ${{ matrix.os }} steps: From a24e57c5c056aba874b952e3a6839a7dbd900bfd Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 8 Nov 2024 19:53:04 -0500 Subject: [PATCH 13/98] [Infra] Update dynamiclinks workflow to use macOS 15 for Xcode 16 (#14061) --- .github/workflows/dynamiclinks.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dynamiclinks.yml b/.github/workflows/dynamiclinks.yml index 777cba16742..61439d6cc3c 100644 --- a/.github/workflows/dynamiclinks.yml +++ b/.github/workflows/dynamiclinks.yml @@ -22,8 +22,11 @@ jobs: strategy: matrix: - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] + include: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -70,7 +73,7 @@ jobs: - os: macos-14 xcode: Xcode_15.4 - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From ec108bb0b91b0ee808f28532c63a320715609a4b Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 11 Nov 2024 07:38:30 -0800 Subject: [PATCH 14/98] [auth] Fix logic inconsistency between 10.x and 11.x (#14067) --- FirebaseAuth/Sources/Swift/User/User.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index 08bf6762414..3371520bdf8 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -1598,18 +1598,22 @@ extension User: NSSecureCoding {} /// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. /// - Parameter forceRefresh func internalGetTokenAsync(forceRefresh: Bool = false) async throws -> String { + var keychainError = false do { let (token, tokenUpdated) = try await tokenService.fetchAccessToken( forcingRefresh: forceRefresh ) if tokenUpdated { if let error = updateKeychain() { + keychainError = true throw error } } return token! } catch { - signOutIfTokenIsInvalid(withError: error) + if !keychainError { + signOutIfTokenIsInvalid(withError: error) + } throw error } } From 7d6269e1387d9327d7f8c94f71a34526d3c25e92 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:42:17 -0500 Subject: [PATCH 15/98] [Auth] Update CHANGELOG.md for #14011 (#14076) --- FirebaseAuth/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index ad38ada6e4b..c9c6dd2776e 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,7 +1,8 @@ -# Unreleased +# 11.5.0 - [fixed] Restore pre-Firebase 11 decoding behavior to prevent users getting logged out when upgrading from Firebase 8.10.0 or earlier to Firebase 11. - (#14011) + Note that this fix will not be in the 11.5.0 zip and Carthage + distributions, but will be included from 11.6.0 onwards. (#14011) # 11.4.0 - [fixed] Restore Firebase 10 behavior by ignoring `nil` display names used From 53801ff9dd48dfd36825fd659402b93fc0826524 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 11:22:38 -0500 Subject: [PATCH 16/98] [Infra] Run Auth quickstart on macOS 15 (#14077) --- .github/workflows/auth.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index a65db1340c8..ffb858b589b 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -221,7 +221,7 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 From 2dd629e9bfcd630e8f944052279b676def15624d Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 12:09:34 -0500 Subject: [PATCH 17/98] [Auth] Add CHANGELOG entry for #14067 (#14078) --- FirebaseAuth/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index c9c6dd2776e..c627b29eed5 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -3,6 +3,10 @@ logged out when upgrading from Firebase 8.10.0 or earlier to Firebase 11. Note that this fix will not be in the 11.5.0 zip and Carthage distributions, but will be included from 11.6.0 onwards. (#14011) +- [fixed] Restore Firebase 10 keychain error handling behavior when retrieving + Firebase Auth tokens, potentially causing user sign-out on Firebase 11. Note + that this fix will not be in the 11.5.0 zip and Carthage distributions, but + will be included from 11.6.0 onwards. (#14067) # 11.4.0 - [fixed] Restore Firebase 10 behavior by ignoring `nil` display names used From 4c855d777b72a334eb13dbbb55e6d0bbca8b88dd Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 12:18:25 -0500 Subject: [PATCH 18/98] [Performance] Add changelog entry for #14048 (#14080) --- FirebasePerformance/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/FirebasePerformance/CHANGELOG.md b/FirebasePerformance/CHANGELOG.md index b0de57ecb27..fd98d461eee 100644 --- a/FirebasePerformance/CHANGELOG.md +++ b/FirebasePerformance/CHANGELOG.md @@ -1,3 +1,9 @@ +# 11.5.0 +- [fixed] Replaced usage of the deprecated `UIApplication.keyWindow` property + with `UIWindow.isKeyWindow`; this API is also available on visionOS. Note that + this fix will not be in the 11.5.0 zip and Carthage distributions, but will be + included from 11.6.0 onwards. (#14048) + # 11.4.0 - [fixed] Fix a crash related to thread sanitization on FPRNetworkTrace class (#13581). From 45db5d1e7fdd37f74ca52ae06038cf2c2599c3da Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 14:06:53 -0500 Subject: [PATCH 19/98] [Infra] Update core workflows to use macOS 15 for Xcode 16 (#14082) --- .github/workflows/core.yml | 23 +++++++++++++---------- .github/workflows/core_internal.yml | 23 +++++++++++++---------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index d3ac22b6b9b..ebd5bdfb3f6 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -22,16 +22,19 @@ jobs: matrix: # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 target: [ios, tvos, macos --skip-tests, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCore.podspec --platforms=${{ matrix.target }} @@ -72,22 +75,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/core_internal.yml b/.github/workflows/core_internal.yml index c9db19c0b3d..9846172135a 100644 --- a/.github/workflows/core_internal.yml +++ b/.github/workflows/core_internal.yml @@ -18,16 +18,19 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCoreInternal.podspec --platforms=${{ matrix.target }} @@ -68,22 +71,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: From 5e8199f10ba1cf8bfcf487a858455ca7a360b86c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 19:08:19 -0500 Subject: [PATCH 20/98] [Infra] Update shared-swift workflow to use macOS 15 for Xcode 16 (#14088) --- .github/workflows/shared-swift.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/shared-swift.yml b/.github/workflows/shared-swift.yml index 40f1d46fa19..6a6785b9752 100644 --- a/.github/workflows/shared-swift.yml +++ b/.github/workflows/shared-swift.yml @@ -24,16 +24,19 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSharedSwift.podspec --platforms=${{ matrix.target }} @@ -67,9 +70,12 @@ jobs: strategy: matrix: target: [iOS, tvOS, macOS, catalyst, watchOS] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: actions/cache/restore@v4 @@ -77,7 +83,7 @@ jobs: path: .build key: ${{needs.spm-package-resolved.outputs.cache_key}} - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Initialize xcodebuild run: scripts/setup_spm_tests.sh - name: Unit Tests From dbdfdc44bee8b8e4eaa5ec27eb12b9338f3f2bc1 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 11 Nov 2024 19:52:06 -0500 Subject: [PATCH 21/98] [Infra] Update messaging workflow to use macOS 15 for Xcode 16 (#14089) --- .github/workflows/messaging.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 8acccc947f0..b253549563f 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -59,24 +59,23 @@ jobs: matrix: podspec: [FirebaseMessagingInterop.podspec, FirebaseMessaging.podspec] target: [ios, tvos, macos --skip-tests, watchos --skip-tests] # skipping tests on mac because of keychain access - os: [macos-14] - include: + build-env: - os: macos-14 xcode: Xcode_15.3 tests: --test-specs=unit - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 tests: --skip-tests - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test - run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} ${{ matrix.tests }} --platforms=${{ matrix.target }} + run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} ${{ matrix.build-env.tests }} --platforms=${{ matrix.target }} spm-package-resolved: env: @@ -115,22 +114,22 @@ jobs: xcode: Xcode_15.4 target: iOS spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS spmbuildonly runs-on: ${{ matrix.os }} steps: @@ -170,8 +169,8 @@ jobs: strategy: matrix: include: - - os: macos-14 - xcode: Xcode_15.3 + - os: macos-15 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 7bdf3bb7bdc6836cde24a2c1c6ca53e4a76aa85a Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:16:31 -0500 Subject: [PATCH 22/98] [Core] Make Timestamp Sendable (#14083) --- FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h b/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h index 375f697338a..0420d4038e6 100644 --- a/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h +++ b/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h @@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN * @see https://github.com/google/protobuf/blob/main/src/google/protobuf/timestamp.proto for the * reference timestamp definition. */ +NS_SWIFT_SENDABLE NS_SWIFT_NAME(Timestamp) @interface FIRTimestamp : NSObject From 9a5b90845c29d20d25983dbb1bfb29c64cb2f43c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 12 Nov 2024 16:31:54 -0500 Subject: [PATCH 23/98] [Infra] Update zip workflow to use macOS 15 for Xcode 16 jobs (#14050) --- .github/workflows/zip.yml | 96 ++++++++++++++++------------------ scripts/zip_quickstart_test.sh | 14 ++++- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 2dd23dcc7fd..1df8854b572 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -111,14 +111,13 @@ jobs: SDK: "ABTesting" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -134,7 +133,7 @@ jobs: find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - uses: actions/checkout@v4 - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup quickstart env: LEGACY: true @@ -173,11 +172,11 @@ jobs: SDK: "Authentication" strategy: matrix: - os: [macos-14] + os: [macos-15] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] include: - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -225,14 +224,13 @@ jobs: SDK: "Config" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -247,7 +245,7 @@ jobs: mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Swift Quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ @@ -277,14 +275,13 @@ jobs: SDK: "Crashlytics" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -300,7 +297,7 @@ jobs: find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - uses: actions/checkout@v4 - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup quickstart env: LEGACY: true @@ -404,14 +401,13 @@ jobs: SDK: "DynamicLinks" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -430,7 +426,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseDynamicLinks/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Swift Quickstart run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - name: Update Environment Variable For DynamicLinks @@ -464,14 +460,13 @@ jobs: SDK: "Firestore" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -493,7 +488,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Install Secret GoogleService-Info.plist run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-firestore.plist.gpg \ quickstart-ios/firestore/GoogleService-Info.plist "$plist_secret" @@ -505,7 +500,7 @@ jobs: - uses: actions/upload-artifact@v4 if: ${{ failure() }} with: - name: quickstart_artifacts_firestore_${{ matrix.artifact }}_${{ matrix.os }} + name: quickstart_artifacts_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} path: quickstart_artifacts_firestore.zip check_framework_firestore_symbols: @@ -549,14 +544,13 @@ jobs: SDK: "InAppMessaging" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -577,7 +571,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseInAppMessaging/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - name: Install Secret GoogleService-Info.plist @@ -606,14 +600,13 @@ jobs: SDK: "Messaging" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -633,7 +626,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseMessaging/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - name: Install Secret GoogleService-Info.plist @@ -662,14 +655,13 @@ jobs: SDK: "Storage" strategy: matrix: - os: [macos-13, macos-14] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] - include: + build-env: - os: macos-13 xcode: Xcode_15.2 - - os: macos-14 - xcode: Xcode_16 - runs-on: ${{ matrix.os }} + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - name: Get framework dir @@ -692,7 +684,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart env: LEGACY: true diff --git a/scripts/zip_quickstart_test.sh b/scripts/zip_quickstart_test.sh index 3fb13ebac88..3b531f8e3f9 100755 --- a/scripts/zip_quickstart_test.sh +++ b/scripts/zip_quickstart_test.sh @@ -30,11 +30,23 @@ if [[ ! -z "$LEGACY" ]]; then cd "Legacy${SAMPLE}Quickstart" fi +xcode_version=$(xcodebuild -version | grep Xcode) +xcode_version="${xcode_version/Xcode /}" +xcode_major="${xcode_version/.*/}" + +if [[ "$xcode_major" -lt 15 ]]; then + device_name="iPhone 14" +elif [[ "$xcode_major" -lt 16 ]]; then + device_name="iPhone 15" +else + device_name="iPhone 16" +fi + ( xcodebuild \ -project ${SAMPLE}Example.xcodeproj \ -scheme ${SAMPLE}Example${SWIFT_SUFFIX} \ --destination 'platform=iOS Simulator,name=iPhone 14' "SWIFT_VERSION=5.3" "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ObjC" "FRAMEWORK_SEARCH_PATHS= \$(PROJECT_DIR)/Firebase/" HEADER_SEARCH_PATHS='$(PROJECT_DIR)/Firebase' \ +-destination "platform=iOS Simulator,name=$device_name" "SWIFT_VERSION=5.3" "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ObjC" "FRAMEWORK_SEARCH_PATHS= \$(PROJECT_DIR)/Firebase/" HEADER_SEARCH_PATHS='$(PROJECT_DIR)/Firebase' \ build \ ) || EXIT_STATUS=$? From 0672366b516764bc7bcaa49550c8cd663ca46749 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:38:53 -0500 Subject: [PATCH 24/98] [Auth] Merge Swift 6 changes into `main` (#14098) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 67 ++++++----- .../Swift/AuthProvider/OAuthProvider.swift | 2 +- .../AuthProvider/PhoneAuthProvider.swift | 12 +- .../Sources/Swift/Backend/AuthBackend.swift | 104 +++++++++--------- .../Swift/Backend/AuthRPCResponse.swift | 7 +- .../Backend/RPC/CreateAuthURIResponse.swift | 2 +- .../Backend/RPC/DeleteAccountResponse.swift | 2 +- .../Backend/RPC/EmailLinkSignInResponse.swift | 2 +- .../Backend/RPC/GetAccountInfoResponse.swift | 2 +- .../RPC/GetOOBConfirmationCodeResponse.swift | 2 +- .../RPC/GetProjectConfigResponse.swift | 2 +- .../RPC/GetRecaptchaConfigResponse.swift | 2 +- .../FinalizeMFAEnrollmentResponse.swift | 2 +- .../Enroll/StartMFAEnrollmentResponse.swift | 2 +- .../SignIn/FinalizeMFASignInResponse.swift | 2 +- .../SignIn/StartMFASignInResponse.swift | 2 +- .../Unenroll/WithdrawMFAResponse.swift | 2 +- .../Backend/RPC/ResetPasswordResponse.swift | 2 +- .../Backend/RPC/RevokeTokenResponse.swift | 2 +- .../Backend/RPC/SecureTokenRequest.swift | 2 +- .../Backend/RPC/SecureTokenResponse.swift | 2 +- .../RPC/SendVerificationTokenResponse.swift | 2 +- .../Backend/RPC/SetAccountInfoResponse.swift | 2 +- .../RPC/SignInWithGameCenterResponse.swift | 2 +- .../Backend/RPC/SignUpNewUserResponse.swift | 2 +- .../Backend/RPC/VerifyAssertionResponse.swift | 2 +- .../RPC/VerifyCustomTokenResponse.swift | 2 +- .../Backend/RPC/VerifyPasswordResponse.swift | 2 +- .../RPC/VerifyPhoneNumberResponse.swift | 2 +- .../Swift/Backend/VerifyClientResponse.swift | 4 +- .../Swift/MultiFactor/MultiFactor.swift | 6 +- .../MultiFactor/MultiFactorResolver.swift | 2 +- .../TOTP/TOTPMultiFactorGenerator.swift | 7 +- .../SystemService/SecureTokenService.swift | 22 ++-- FirebaseAuth/Sources/Swift/User/User.swift | 67 ++++++----- .../Swift/User/UserProfileUpdate.swift | 22 ++-- .../Utilities/AuthRecaptchaVerifier.swift | 8 +- .../Swift/Utilities/AuthWebUtils.swift | 5 +- .../ViewControllers/AuthViewController.swift | 4 +- .../Tests/Unit/AuthBackendTests.swift | 40 +++---- FirebaseAuth/Tests/Unit/AuthTests.swift | 3 +- .../Tests/Unit/CreateAuthURITests.swift | 4 +- .../Tests/Unit/DeleteAccountTests.swift | 2 +- .../Tests/Unit/EmailLinkSignInTests.swift | 6 +- .../Tests/Unit/GetAccountInfoTests.swift | 2 +- .../Unit/GetOOBConfirmationCodeTests.swift | 4 +- .../Tests/Unit/GetProjectConfigTests.swift | 2 +- .../Tests/Unit/GetRecaptchaConfigTests.swift | 4 +- .../Tests/Unit/OAuthProviderTests.swift | 4 + .../Tests/Unit/PhoneAuthProviderTests.swift | 2 +- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 9 +- .../Tests/Unit/ResetPasswordTests.swift | 2 +- .../Tests/Unit/RevokeTokenTests.swift | 2 +- .../Unit/SendVerificationCodeTests.swift | 2 +- .../Tests/Unit/SetAccountInfoTests.swift | 2 +- .../Unit/SignInWithGameCenterTests.swift | 2 +- .../Tests/Unit/SignUpNewUserTests.swift | 2 +- FirebaseAuth/Tests/Unit/UserTests.swift | 97 ++++++++-------- .../Tests/Unit/VerifyAssertionTests.swift | 4 +- .../Tests/Unit/VerifyClientTests.swift | 2 +- .../Tests/Unit/VerifyCustomTokenTests.swift | 2 +- .../Tests/Unit/VerifyPasswordTests.swift | 2 +- .../Tests/Unit/VerifyPhoneNumberTests.swift | 4 +- 63 files changed, 309 insertions(+), 283 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 19e8029974b..e5ccdaafac7 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -123,11 +123,12 @@ extension Auth: AuthInterop { return } // Call back with current user token. - currentUser.internalGetToken(forceRefresh: forceRefresh) { token, error in - DispatchQueue.main.async { - callback(token, error) + currentUser + .internalGetToken(forceRefresh: forceRefresh, backend: strongSelf.backend) { token, error in + DispatchQueue.main.async { + callback(token, error) + } } - } } } @@ -292,7 +293,7 @@ extension Auth: AuthInterop { requestConfiguration: self.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) Auth.wrapMainAsync(callback: completion, withParam: response.signinMethods, error: nil) } catch { Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) @@ -395,7 +396,7 @@ extension Auth: AuthInterop { let response = try await injectRecaptcha(request: request, action: AuthRecaptchaAction.signInWithPassword) #else - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) #endif return try await completeSignIn( withAccessToken: response.idToken, @@ -709,7 +710,7 @@ extension Auth: AuthInterop { let request = SignUpNewUserRequest(requestConfiguration: self.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) let user = try await self.completeSignIn( withAccessToken: response.idToken, accessTokenExpirationDate: response.approximateExpirationDate, @@ -771,7 +772,7 @@ extension Auth: AuthInterop { requestConfiguration: self.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) let user = try await self.completeSignIn( withAccessToken: response.idToken, accessTokenExpirationDate: response.approximateExpirationDate, @@ -881,7 +882,7 @@ extension Auth: AuthInterop { if let inResponse { response = inResponse } else { - response = try await AuthBackend.call(with: request) + response = try await self.backend.call(with: request) } let user = try await self.completeSignIn( withAccessToken: response.idToken, @@ -993,7 +994,7 @@ extension Auth: AuthInterop { requestConfiguration: self.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) let operation = ActionCodeInfo.actionCodeOperation(forRequestType: response.requestType) guard let email = response.email else { @@ -1433,7 +1434,7 @@ extension Auth: AuthInterop { /// complete, or fails. Invoked asynchronously on the main thread in the future. @objc open func revokeToken(withAuthorizationCode authorizationCode: String, completion: ((Error?) -> Void)? = nil) { - currentUser?.internalGetToken { idToken, error in + currentUser?.internalGetToken(backend: backend) { idToken, error in if let error { Auth.wrapMainAsync(completion, error) return @@ -1613,7 +1614,9 @@ extension Auth: AuthInterop { // MARK: Internal methods - init(app: FirebaseApp, keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal()) { + init(app: FirebaseApp, + keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal(), + backend: AuthBackend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer())) { Auth.setKeychainServiceNameForApp(app) self.app = app mainBundleUrlTypes = Bundle.main @@ -1638,6 +1641,7 @@ extension Auth: AuthInterop { auth: nil, heartbeatLogger: app.heartbeatLogger, appCheck: appCheck) + self.backend = backend super.init() requestConfiguration.auth = self @@ -1911,17 +1915,18 @@ extension Auth: AuthInterop { return } let uid = strongSelf.currentUser?.uid - strongSelf.currentUser?.internalGetToken(forceRefresh: true) { token, error in - if strongSelf.currentUser?.uid != uid { - return - } - if error != nil { - // Kicks off exponential back off logic to retry failed attempt. Starts with one minute - // delay (60 seconds) if this is the first failed attempt. - let rescheduleDelay = retry ? min(delay * 2, 16 * 60) : 60 - strongSelf.scheduleAutoTokenRefresh(withDelay: rescheduleDelay, retry: true) + strongSelf.currentUser? + .internalGetToken(forceRefresh: true, backend: strongSelf.backend) { token, error in + if strongSelf.currentUser?.uid != uid { + return + } + if error != nil { + // Kicks off exponential back off logic to retry failed attempt. Starts with one minute + // delay (60 seconds) if this is the first failed attempt. + let rescheduleDelay = retry ? min(delay * 2, 16 * 60) : 60 + strongSelf.scheduleAutoTokenRefresh(withDelay: rescheduleDelay, retry: true) + } } - } } } @@ -2075,7 +2080,7 @@ extension Auth: AuthInterop { requestConfiguration: requestConfiguration) request.autoCreate = !isReauthentication credential.prepare(request) - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) if response.needConfirmation { let email = response.email let credential = OAuthCredential(withVerifyAssertionResponse: response) @@ -2114,7 +2119,7 @@ extension Auth: AuthInterop { phoneNumber: phoneNumber, operation: operation, requestConfiguration: requestConfiguration) - return try await AuthBackend.call(with: request) + return try await backend.call(with: request) case let .verification(verificationID, code): guard verificationID.count > 0 else { throw AuthErrorUtils.missingVerificationIDError(message: nil) @@ -2126,7 +2131,7 @@ extension Auth: AuthInterop { verificationCode: code, operation: operation, requestConfiguration: requestConfiguration) - return try await AuthBackend.call(with: request) + return try await backend.call(with: request) } } #endif @@ -2152,7 +2157,7 @@ extension Auth: AuthInterop { timestamp: credential.timestamp, displayName: credential.displayName, requestConfiguration: requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) let user = try await completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: response .approximateExpirationDate, @@ -2184,7 +2189,7 @@ extension Auth: AuthInterop { let request = EmailLinkSignInRequest(email: email, oobCode: actionCode, requestConfiguration: requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) let user = try await completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: response .approximateExpirationDate, @@ -2242,7 +2247,7 @@ extension Auth: AuthInterop { private func wrapAsyncRPCTask(_ request: any AuthRPCRequest, _ callback: ((Error?) -> Void)?) { Task { do { - let _ = try await AuthBackend.call(with: request) + let _ = try await self.backend.call(with: request) Auth.wrapMainAsync(callback, nil) } catch { Auth.wrapMainAsync(callback, error) @@ -2294,7 +2299,7 @@ extension Auth: AuthInterop { action: action) } else { do { - return try await AuthBackend.call(with: request) + return try await backend.call(with: request) } catch { let nsError = error as NSError if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError, @@ -2313,7 +2318,7 @@ extension Auth: AuthInterop { } } } - return try await AuthBackend.call(with: request) + return try await backend.call(with: request) } #endif @@ -2330,6 +2335,8 @@ extension Auth: AuthInterop { /// Auth's backend. var requestConfiguration: AuthRequestConfiguration + let backend: AuthBackend + #if os(iOS) /// The manager for APNs tokens used by phone number auth. diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift index 01437d49891..b8cca1f5fca 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift @@ -413,7 +413,7 @@ import Foundation private func getHeadfulLiteUrl(eventID: String, sessionID: String) async throws -> URL? { let authDomain = try await AuthWebUtils - .fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration) + .fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration, backend: auth.backend) let bundleID = Bundle.main.bundleIdentifier let clientID = auth.app?.options.clientID let appID = auth.app?.options.googleAppID diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 32d15499f74..2a1de385aa4 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -217,7 +217,7 @@ import Foundation .requestConfiguration) do { - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) return response.verificationID } catch { return try await handleVerifyErrorWithRetry(error: error, @@ -245,7 +245,7 @@ import Foundation requestConfiguration: auth.requestConfiguration ) - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) return response.verificationID } guard let session else { @@ -263,7 +263,7 @@ import Foundation let request = StartMFAEnrollmentRequest(idToken: idToken, enrollmentInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) return response.phoneSessionInfo?.sessionInfo } else { let request = StartMFASignInRequest(MFAPendingCredential: session.mfaPendingCredential, @@ -271,7 +271,7 @@ import Foundation signInInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) return response.responseInfo?.sessionInfo } } catch { @@ -328,7 +328,7 @@ import Foundation isSandbox: token.type == AuthAPNSTokenType.sandbox, requestConfiguration: auth.requestConfiguration) do { - let verifyResponse = try await AuthBackend.call(with: request) + let verifyResponse = try await auth.backend.call(with: request) guard let receipt = verifyResponse.receipt, let timeout = verifyResponse.suggestedTimeOutDate?.timeIntervalSinceNow else { fatalError("Internal Auth Error: invalid VerifyClientResponse") @@ -436,7 +436,7 @@ import Foundation /// - Parameter eventID: The event ID used for this purpose. private func reCAPTCHAURL(withEventID eventID: String) async throws -> URL? { let authDomain = try await AuthWebUtils - .fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration) + .fetchAuthDomain(withRequestConfiguration: auth.requestConfiguration, backend: auth.backend) let bundleID = Bundle.main.bundleIdentifier let clientID = auth.app?.options.clientID let appID = auth.app?.options.googleAppID diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 58fb6c4be80..85802392052 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -32,21 +32,7 @@ class AuthBackend: AuthBackendProtocol { return "FirebaseAuth.iOS/\(FirebaseVersion()) \(GTMFetcherStandardUserAgentString(nil))" } - static func call(with request: T) async throws -> T.Response { - return try await shared.call(with: request) - } - - static func setTestRPCIssuer(issuer: AuthBackendRPCIssuer) { - shared.rpcIssuer = issuer - } - - static func resetRPCIssuer() { - shared.rpcIssuer = AuthBackendRPCIssuer() - } - - private static let shared: AuthBackend = .init(rpcIssuer: AuthBackendRPCIssuer()) - - private var rpcIssuer: any AuthBackendRPCIssuerProtocol + private let rpcIssuer: any AuthBackendRPCIssuerProtocol init(rpcIssuer: any AuthBackendRPCIssuerProtocol) { self.rpcIssuer = rpcIssuer @@ -251,66 +237,74 @@ class AuthBackend: AuthBackendProtocol { } dictionary = decodedDictionary - var response = T.Response() + let responseResult = Result { + try T.Response(dictionary: dictionary) + } // At this point we either have an error with successfully decoded // details in the body, or we have a response which must pass further // validation before we know it's truly successful. We deal with the // case where we have an error with successfully decoded error details // first: - if error != nil { - if let errorDictionary = dictionary["error"] as? [String: AnyHashable] { - if let errorMessage = errorDictionary["message"] as? String { - if let clientError = Self.clientError( - withServerErrorMessage: errorMessage, - errorDictionary: errorDictionary, - response: response, - error: error - ) { - throw clientError + switch responseResult { + case let .success(response): + try propagateError(error, dictionary: dictionary, response: response) + // In case returnIDPCredential of a verifyAssertion request is set to + // @YES, the server may return a 200 with a response that may contain a + // server error. + if let verifyAssertionRequest = request as? VerifyAssertionRequest { + if verifyAssertionRequest.returnIDPCredential { + if let errorMessage = dictionary["errorMessage"] as? String { + if let clientError = Self.clientError( + withServerErrorMessage: errorMessage, + errorDictionary: dictionary, + response: response, + error: error + ) { + throw clientError + } } } - // Not a message we know, return the message directly. - throw AuthErrorUtils.unexpectedErrorResponse( - deserializedResponse: errorDictionary, - underlyingError: error - ) } - // No error message at all, return the decoded response. + return response + case let .failure(failure): + try propagateError(error, dictionary: dictionary, response: nil) throw AuthErrorUtils - .unexpectedErrorResponse(deserializedResponse: dictionary, underlyingError: error) + .RPCResponseDecodingError(deserializedResponse: dictionary, underlyingError: failure) } + } - // Finally, we try to populate the response object with the JSON values. - do { - try response.setFields(dictionary: dictionary) - } catch { - throw AuthErrorUtils - .RPCResponseDecodingError(deserializedResponse: dictionary, underlyingError: error) + private func propagateError(_ error: Error?, dictionary: [String: AnyHashable], + response: AuthRPCResponse?) throws { + guard let error else { + return } - // In case returnIDPCredential of a verifyAssertion request is set to - // @YES, the server may return a 200 with a response that may contain a - // server error. - if let verifyAssertionRequest = request as? VerifyAssertionRequest { - if verifyAssertionRequest.returnIDPCredential { - if let errorMessage = dictionary["errorMessage"] as? String { - if let clientError = Self.clientError( - withServerErrorMessage: errorMessage, - errorDictionary: dictionary, - response: response, - error: error - ) { - throw clientError - } + + if let errorDictionary = dictionary["error"] as? [String: AnyHashable] { + if let errorMessage = errorDictionary["message"] as? String { + if let clientError = Self.clientError( + withServerErrorMessage: errorMessage, + errorDictionary: errorDictionary, + response: response, + error: error + ) { + throw clientError } } + // Not a message we know, return the message directly. + throw AuthErrorUtils.unexpectedErrorResponse( + deserializedResponse: errorDictionary, + underlyingError: error + ) } - return response + // No error message at all, return the decoded response. + throw AuthErrorUtils + .unexpectedErrorResponse(deserializedResponse: dictionary, underlyingError: error) } private static func clientError(withServerErrorMessage serverErrorMessage: String, errorDictionary: [String: Any], - response: AuthRPCResponse, + response: AuthRPCResponse?, error: Error?) -> Error? { let split = serverErrorMessage.split(separator: ":") let shortErrorMessage = split.first?.trimmingCharacters(in: .whitespacesAndNewlines) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthRPCResponse.swift b/FirebaseAuth/Sources/Swift/Backend/AuthRPCResponse.swift index 0b7ea8a3a52..00d302e5775 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthRPCResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthRPCResponse.swift @@ -15,14 +15,11 @@ import Foundation protocol AuthRPCResponse: Sendable { - /// Bare initializer for a response. - init() - - /// Sets the response instance from the decoded JSON response. + /// Initializes the response instance from the decoded JSON response. /// - Parameter dictionary: The dictionary decoded from HTTP JSON response. /// - Parameter error: An out field for an error which occurred constructing the request. /// - Returns: Whether the operation was successful or not. - mutating func setFields(dictionary: [String: AnyHashable]) throws + init(dictionary: [String: AnyHashable]) throws /// This optional method allows response classes to create client errors given a short error /// message and a detail error message from the server. diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIResponse.swift index 019a92f4b90..66b1ad95023 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIResponse.swift @@ -35,7 +35,7 @@ struct CreateAuthURIResponse: AuthRPCResponse { /// A list of sign-in methods available for the passed identifier. var signinMethods: [String] = [] - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { providerID = dictionary["providerId"] as? String authURI = dictionary["authUri"] as? String registered = dictionary["registered"] as? Bool ?? false diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountResponse.swift index 4b6802dafb3..d3a34371caa 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountResponse.swift @@ -18,5 +18,5 @@ import Foundation /// /// See https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount struct DeleteAccountResponse: AuthRPCResponse { - mutating func setFields(dictionary: [String: AnyHashable]) throws {} + init(dictionary: [String: AnyHashable]) throws {} } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInResponse.swift index 608c38237cc..0fb80a8f9c2 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInResponse.swift @@ -40,7 +40,7 @@ struct EmailLinkSignInResponse: AuthRPCResponse, AuthMFAResponse { /// Info on which multi-factor authentication providers are enabled. private(set) var mfaInfo: [AuthProtoMFAEnrollment]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { email = dictionary["email"] as? String idToken = dictionary["idToken"] as? String isNewUser = dictionary["isNewUser"] as? Bool ?? false diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoResponse.swift index e0f9c463959..4fb5795bcd5 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoResponse.swift @@ -139,7 +139,7 @@ struct GetAccountInfoResponse: AuthRPCResponse { /// The requested users' profiles. var users: [Self.User]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { guard let usersData = dictionary["users"] as? [[String: AnyHashable]] else { throw AuthErrorUtils.unexpectedResponse(deserializedResponse: dictionary) } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeResponse.swift index 91721fd659e..dcfba9d5212 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeResponse.swift @@ -19,7 +19,7 @@ private let kOOBCodeKey = "oobCode" struct GetOOBConfirmationCodeResponse: AuthRPCResponse { var OOBCode: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { OOBCode = dictionary[kOOBCodeKey] as? String } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigResponse.swift index b9fb18771b7..65091a46c7e 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigResponse.swift @@ -19,7 +19,7 @@ struct GetProjectConfigResponse: AuthRPCResponse { var authorizedDomains: [String]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { projectID = dictionary["projectId"] as? String if let authorizedDomains = dictionary["authorizedDomains"] as? String, let data = authorizedDomains.data(using: .utf8) { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift index b62bd84a695..327ff3751a2 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigResponse.swift @@ -18,7 +18,7 @@ struct GetRecaptchaConfigResponse: AuthRPCResponse { private(set) var recaptchaKey: String? private(set) var enforcementState: [[String: String]]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { recaptchaKey = dictionary["recaptchaKey"] as? String enforcementState = dictionary["recaptchaEnforcementState"] as? [[String: String]] } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentResponse.swift index bdd3ce89d31..595e3b45952 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentResponse.swift @@ -21,7 +21,7 @@ struct FinalizeMFAEnrollmentResponse: AuthRPCResponse { private(set) var phoneSessionInfo: AuthProtoFinalizeMFAPhoneResponseInfo? private(set) var totpSessionInfo: AuthProtoFinalizeMFATOTPEnrollmentResponseInfo? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String refreshToken = dictionary["refreshToken"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentResponse.swift index dadbb9a15be..7c91b54227c 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentResponse.swift @@ -19,7 +19,7 @@ struct StartMFAEnrollmentResponse: AuthRPCResponse { private(set) var phoneSessionInfo: AuthProtoStartMFAPhoneResponseInfo? private(set) var totpSessionInfo: AuthProtoStartMFATOTPEnrollmentResponseInfo? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { if let data = dictionary["phoneSessionInfo"] as? [String: AnyHashable] { phoneSessionInfo = AuthProtoStartMFAPhoneResponseInfo(dictionary: data) } else if let data = dictionary["totpSessionInfo"] as? [String: AnyHashable] { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInResponse.swift index 032dab3ff86..850a969e6cd 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInResponse.swift @@ -19,7 +19,7 @@ struct FinalizeMFASignInResponse: AuthRPCResponse { var IDToken: String? var refreshToken: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { IDToken = dictionary["idToken"] as? String refreshToken = dictionary["refreshToken"] as? String } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift index cc597172010..291821c58f9 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift @@ -18,7 +18,7 @@ import Foundation struct StartMFASignInResponse: AuthRPCResponse { var responseInfo: AuthProtoStartMFAPhoneResponseInfo? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { if let data = dictionary["phoneResponseInfo"] as? [String: AnyHashable] { responseInfo = AuthProtoStartMFAPhoneResponseInfo(dictionary: data) } else { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFAResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFAResponse.swift index 4744a6965ee..27bcd0d32e4 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFAResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFAResponse.swift @@ -18,7 +18,7 @@ struct WithdrawMFAResponse: AuthRPCResponse { var idToken: String? var refreshToken: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String refreshToken = dictionary["refreshToken"] as? String } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordResponse.swift index 22cb703e5ad..1744dfc34cf 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordResponse.swift @@ -34,7 +34,7 @@ struct ResetPasswordResponse: AuthRPCResponse { /// The type of request as returned by the backend. var requestType: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { email = dictionary["email"] as? String requestType = dictionary["requestType"] as? String verifiedEmail = dictionary["newEmail"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenResponse.swift index 7e6bf0e7378..900959ccbe1 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenResponse.swift @@ -15,7 +15,7 @@ import Foundation struct RevokeTokenResponse: AuthRPCResponse { - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { // Nothing to set or throw. } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift index c07d60c7a60..e7fa5ee57e5 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift @@ -59,7 +59,7 @@ private var gAPIHost = "securetoken.googleapis.com" /// Represents the parameters for the token endpoint. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -struct SecureTokenRequest: AuthRPCRequest { +class SecureTokenRequest: AuthRPCRequest { typealias Response = SecureTokenResponse /// The type of grant requested. diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenResponse.swift index 86291a60015..44409ba92d4 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenResponse.swift @@ -37,7 +37,7 @@ struct SecureTokenResponse: AuthRPCResponse { var expectedKind: String? { nil } - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { refreshToken = dictionary[kRefreshTokenKey] as? String self.accessToken = dictionary[kAccessTokenKey] as? String idToken = dictionary[kIDTokenKey] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index f9e6872cfcb..7b1815c5925 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -17,7 +17,7 @@ import Foundation struct SendVerificationCodeResponse: AuthRPCResponse { var verificationID: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { verificationID = dictionary["sessionInfo"] as? String } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoResponse.swift index c1b932b83c2..0a036d95195 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoResponse.swift @@ -60,7 +60,7 @@ struct SetAccountInfoResponse: AuthRPCResponse { /// The refresh token from Secure Token Service. var refreshToken: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { email = dictionary["email"] as? String displayName = dictionary["displayName"] as? String idToken = dictionary["idToken"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterResponse.swift index d291384ff49..cc81610b17b 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterResponse.swift @@ -25,7 +25,7 @@ struct SignInWithGameCenterResponse: AuthRPCResponse { var isNewUser: Bool = false var displayName: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String refreshToken = dictionary["refreshToken"] as? String localID = dictionary["localId"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserResponse.swift index 7b25c6a6f8c..21f359b0f1a 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserResponse.swift @@ -26,7 +26,7 @@ struct SignUpNewUserResponse: AuthRPCResponse { /// The refresh token from Secure Token Service. var refreshToken: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String if let approximateExpirationDate = dictionary["expiresIn"] as? String { self diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionResponse.swift index c031aa22c43..9caa9d38e35 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionResponse.swift @@ -132,7 +132,7 @@ struct VerifyAssertionResponse: AuthRPCResponse, AuthMFAResponse { private(set) var mfaInfo: [AuthProtoMFAEnrollment]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { federatedID = dictionary["federatedId"] as? String providerID = dictionary["providerId"] as? String localID = dictionary["localId"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenResponse.swift index 5c66bf6ba74..9cf1ec0924f 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenResponse.swift @@ -30,7 +30,7 @@ struct VerifyCustomTokenResponse: AuthRPCResponse { /// Flag indicating that the user signing in is a new user and not a returning user. var isNewUser: Bool = false - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String if let dateString = dictionary["expiresIn"] as? NSString { approximateExpirationDate = Date(timeIntervalSinceNow: dateString.doubleValue) diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordResponse.swift index ba93ac1e0a5..22a3d87e958 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordResponse.swift @@ -51,7 +51,7 @@ struct VerifyPasswordResponse: AuthRPCResponse, AuthMFAResponse { private(set) var mfaInfo: [AuthProtoMFAEnrollment]? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { localID = dictionary["localId"] as? String email = dictionary["email"] as? String displayName = dictionary["displayName"] as? String diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberResponse.swift index b5efb964c73..a187824b7dd 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberResponse.swift @@ -43,7 +43,7 @@ struct VerifyPhoneNumberResponse: AuthRPCResponse { nil } - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { idToken = dictionary["idToken"] as? String refreshToken = dictionary["refreshToken"] as? String isNewUser = (dictionary["isNewUser"] as? Bool) ?? false diff --git a/FirebaseAuth/Sources/Swift/Backend/VerifyClientResponse.swift b/FirebaseAuth/Sources/Swift/Backend/VerifyClientResponse.swift index 683ed33a01f..a468197948f 100644 --- a/FirebaseAuth/Sources/Swift/Backend/VerifyClientResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/VerifyClientResponse.swift @@ -15,15 +15,13 @@ import Foundation struct VerifyClientResponse: AuthRPCResponse { - init() {} - /// Receipt that the APNS token was successfully validated with APNS. private(set) var receipt: String? /// The date after which delivery of the silent push notification is considered to have failed. private(set) var suggestedTimeOutDate: Date? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { receipt = dictionary["receipt"] as? String let suggestedTimeout = dictionary["suggestedTimeout"] if let string = suggestedTimeout as? String, diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift index f3dd5b26981..c60f353e362 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift @@ -88,7 +88,7 @@ import Foundation .requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) do { let user = try await auth.completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: nil, @@ -139,7 +139,7 @@ import Foundation Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) do { let user = try await auth.completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: nil, @@ -217,7 +217,7 @@ import Foundation requestConfiguration: user.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) do { let user = try await auth.completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: nil, diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift index 64b8bdda693..366ccc02023 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift @@ -72,7 +72,7 @@ import Foundation ) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.auth.backend.call(with: request) let user = try await self.auth.completeSignIn(withAccessToken: response.idToken, accessTokenExpirationDate: nil, refreshToken: response.refreshToken, diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift index 4fc574caedb..bf3b07634ca 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift @@ -31,8 +31,7 @@ import Foundation @objc(generateSecretWithMultiFactorSession:completion:) open class func generateSecret(with session: MultiFactorSession, completion: @escaping (TOTPSecret?, Error?) -> Void) { - guard let currentUser = session.currentUser, - let requestConfiguration = currentUser.auth?.requestConfiguration else { + guard let currentUser = session.currentUser, let auth = currentUser.auth else { let error = AuthErrorUtils.error(code: AuthErrorCode.internalError, userInfo: [NSLocalizedDescriptionKey: "Invalid ID token."]) @@ -42,10 +41,10 @@ import Foundation let totpEnrollmentInfo = AuthProtoStartMFATOTPEnrollmentRequestInfo() let request = StartMFAEnrollmentRequest(idToken: session.idToken, totpEnrollmentInfo: totpEnrollmentInfo, - requestConfiguration: requestConfiguration) + requestConfiguration: auth.requestConfiguration) Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await auth.backend.call(with: request) if let totpSessionInfo = response.totpSessionInfo { let secret = TOTPSecret(secretKey: totpSessionInfo.sharedSecretKey, hashingAlgorithm: totpSessionInfo.hashingAlgorithm, diff --git a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift index dd9e6dbde13..6bdee4c395a 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift @@ -25,12 +25,13 @@ actor SecureTokenServiceInternal { /// - Parameter forceRefresh: Forces the token to be refreshed. /// - Returns : A tuple with the token and flag of whether it was updated. func fetchAccessToken(forcingRefresh forceRefresh: Bool, - service: SecureTokenService) async throws -> (String?, Bool) { + service: SecureTokenService, + backend: AuthBackend) async throws -> (String?, Bool) { if !forceRefresh, hasValidAccessToken(service: service) { return (service.accessToken, false) } else { AuthLog.logDebug(code: "I-AUT000017", message: "Fetching new token from backend.") - return try await requestAccessToken(retryIfExpired: true, service: service) + return try await requestAccessToken(retryIfExpired: true, service: service, backend: backend) } } @@ -41,7 +42,8 @@ actor SecureTokenServiceInternal { /// /// - Returns: Token and Bool indicating if update occurred. private func requestAccessToken(retryIfExpired: Bool, - service: SecureTokenService) async throws -> (String?, Bool) { + service: SecureTokenService, + backend: AuthBackend) async throws -> (String?, Bool) { // TODO: This was a crash in ObjC SDK, should it callback with an error? guard let refreshToken = service.refreshToken, let requestConfiguration = service.requestConfiguration else { @@ -50,7 +52,7 @@ actor SecureTokenServiceInternal { let request = SecureTokenRequest.refreshRequest(refreshToken: refreshToken, requestConfiguration: requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) var tokenUpdated = false if let newAccessToken = response.accessToken, newAccessToken.count > 0, @@ -67,7 +69,11 @@ actor SecureTokenServiceInternal { if expirationDate.timeIntervalSinceNow <= kFiveMinutes { // We only retry once, to avoid an infinite loop in the case that an end-user has // their local time skewed by over an hour. - return try await requestAccessToken(retryIfExpired: false, service: service) + return try await requestAccessToken( + retryIfExpired: false, + service: service, + backend: backend + ) } } } @@ -152,8 +158,10 @@ class SecureTokenService: NSObject, NSSecureCoding { /// Invoked asynchronously on the auth global work queue in the future. /// - Parameter forceRefresh: Forces the token to be refreshed. /// - Returns : A tuple with the token and flag of whether it was updated. - func fetchAccessToken(forcingRefresh forceRefresh: Bool) async throws -> (String?, Bool) { - return try await internalService.fetchAccessToken(forcingRefresh: forceRefresh, service: self) + func fetchAccessToken(forcingRefresh forceRefresh: Bool, + backend: AuthBackend) async throws -> (String?, Bool) { + return try await internalService + .fetchAccessToken(forcingRefresh: forceRefresh, service: self, backend: backend) } // MARK: NSSecureCoding diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index 3371520bdf8..fccd96ab088 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -49,6 +49,9 @@ extension User: NSSecureCoding {} var providerDataRaw: [String: UserInfoImpl] + /// The backend service for the given instance. + private(set) var backend: AuthBackend + /// Metadata associated with the Firebase user in question. @objc public private(set) var metadata: UserMetadata @@ -583,7 +586,7 @@ extension User: NSSecureCoding {} open func getIDTokenResult(forcingRefresh: Bool, completion: ((AuthTokenResult?, Error?) -> Void)?) { kAuthGlobalWorkQueue.async { - self.internalGetToken(forceRefresh: forcingRefresh) { token, error in + self.internalGetToken(forceRefresh: forcingRefresh, backend: self.backend) { token, error in var tokenResult: AuthTokenResult? if let token { do { @@ -866,7 +869,7 @@ extension User: NSSecureCoding {} open func sendEmailVerification(with actionCodeSettings: ActionCodeSettings? = nil, completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { - self.internalGetToken { accessToken, error in + self.internalGetToken(backend: self.backend) { accessToken, error in if let error { User.callInMainThreadWithError(callback: completion, error: error) return @@ -884,7 +887,7 @@ extension User: NSSecureCoding {} ) Task { do { - let _ = try await AuthBackend.call(with: request) + let _ = try await self.backend.call(with: request) User.callInMainThreadWithError(callback: completion, error: nil) } catch { self.signOutIfTokenIsInvalid(withError: error) @@ -931,7 +934,7 @@ extension User: NSSecureCoding {} /// is complete, or fails. Invoked asynchronously on the main thread in the future. @objc open func delete(completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { - self.internalGetToken { accessToken, error in + self.internalGetToken(backend: self.backend) { accessToken, error in if let error { User.callInMainThreadWithError(callback: completion, error: error) return @@ -946,7 +949,7 @@ extension User: NSSecureCoding {} requestConfiguration: requestConfiguration) Task { do { - let _ = try await AuthBackend.call(with: request) + let _ = try await self.backend.call(with: request) try self.auth?.signOutByForce(withUserID: self.uid) User.callInMainThreadWithError(callback: completion, error: nil) } catch { @@ -996,7 +999,7 @@ extension User: NSSecureCoding {} actionCodeSettings: ActionCodeSettings? = nil, completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { - self.internalGetToken { accessToken, error in + self.internalGetToken(backend: self.backend) { accessToken, error in if let error { User.callInMainThreadWithError(callback: completion, error: error) return @@ -1015,7 +1018,7 @@ extension User: NSSecureCoding {} ) Task { do { - let _ = try await AuthBackend.call(with: request) + let _ = try await self.backend.call(with: request) User.callInMainThreadWithError(callback: completion, error: nil) } catch { User.callInMainThreadWithError(callback: completion, error: error) @@ -1054,7 +1057,8 @@ extension User: NSSecureCoding {} return tokenService.accessTokenExpirationDate } - init(withTokenService tokenService: SecureTokenService) { + init(withTokenService tokenService: SecureTokenService, backend: AuthBackend) { + self.backend = backend providerDataRaw = [:] userProfileUpdate = UserProfileUpdate() self.tokenService = tokenService @@ -1083,16 +1087,16 @@ extension User: NSSecureCoding {} accessToken: accessToken, accessTokenExpirationDate: accessTokenExpirationDate, refreshToken: refreshToken) - let user = User(withTokenService: tokenService) + let user = User(withTokenService: tokenService, backend: auth.backend) user.auth = auth user.tenantID = auth.tenantID user.requestConfiguration = auth.requestConfiguration - let accessToken2 = try await user.internalGetTokenAsync() + let accessToken2 = try await user.internalGetTokenAsync(backend: user.backend) let getAccountInfoRequest = GetAccountInfoRequest( accessToken: accessToken2, requestConfiguration: user.requestConfiguration ) - let response = try await AuthBackend.call(with: getAccountInfoRequest) + let response = try await auth.backend.call(with: getAccountInfoRequest) user.isAnonymous = anonymous user.update(withGetAccountInfoResponse: response) return user @@ -1137,12 +1141,13 @@ extension User: NSSecureCoding {} /// A weak reference to an `Auth` instance associated with this instance. weak var auth: Auth? { set { - _auth = newValue - guard let requestConfiguration = auth?.requestConfiguration else { - fatalError("Firebase Auth Internal Error: nil requestConfiguration when initializing User") + guard let newValue else { + fatalError("Firebase Auth Internal Error: Set user's auth property with non-nil instance.") } + _auth = newValue + requestConfiguration = newValue.requestConfiguration tokenService.requestConfiguration = requestConfiguration - self.requestConfiguration = requestConfiguration + backend = newValue.backend } get { return _auth } } @@ -1173,12 +1178,12 @@ extension User: NSSecureCoding {} // The list of providers need to be updated for the newly added email-password provider. Task { do { - let accessToken = try await self.internalGetTokenAsync() + let accessToken = try await self.internalGetTokenAsync(backend: self.backend) if let requestConfiguration = self.auth?.requestConfiguration { let getAccountInfoRequest = GetAccountInfoRequest(accessToken: accessToken, requestConfiguration: requestConfiguration) do { - let accountInfoResponse = try await AuthBackend.call(with: getAccountInfoRequest) + let accountInfoResponse = try await self.backend.call(with: getAccountInfoRequest) if let users = accountInfoResponse.users { for userAccountInfo in users { // Set the account to non-anonymous if there are any providers, even if @@ -1313,7 +1318,7 @@ extension User: NSSecureCoding {} private func internalUpdateOrLinkPhoneNumber(credential: PhoneAuthCredential, isLinkOperation: Bool, completion: @escaping (Error?) -> Void) { - internalGetToken { accessToken, error in + internalGetToken(backend: backend) { accessToken, error in if let error { completion(error) return @@ -1335,7 +1340,7 @@ extension User: NSSecureCoding {} request.accessToken = accessToken Task { do { - let verifyResponse = try await AuthBackend.call(with: request) + let verifyResponse = try await self.backend.call(with: request) guard let idToken = verifyResponse.idToken, let refreshToken = verifyResponse.refreshToken else { fatalError("Internal Auth Error: missing token in internalUpdateOrLinkPhoneNumber") @@ -1375,7 +1380,7 @@ extension User: NSSecureCoding {} password: String, authResult: AuthDataResult, _ completion: ((AuthDataResult?, Error?) -> Void)?) { - internalGetToken { accessToken, error in + internalGetToken(backend: backend) { accessToken, error in guard let requestConfiguration = self.auth?.requestConfiguration else { fatalError("Internal auth error: missing auth on User") } @@ -1394,7 +1399,7 @@ extension User: NSSecureCoding {} action: AuthRecaptchaAction .signUpPassword) #else - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) #endif guard let refreshToken = response.refreshToken, let idToken = response.idToken else { @@ -1437,7 +1442,7 @@ extension User: NSSecureCoding {} let result = AuthDataResult(withUser: self, additionalUserInfo: nil) link(withEmail: emailCredential.email, password: password, authResult: result, completion) case let .link(link): - internalGetToken { accessToken, error in + internalGetToken(backend: backend) { accessToken, error in var queryItems = AuthWebUtils.parseURL(link) if link.count == 0 { if let urlComponents = URLComponents(string: link), @@ -1455,7 +1460,7 @@ extension User: NSSecureCoding {} request.idToken = accessToken Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) guard let idToken = response.idToken, let refreshToken = response.refreshToken else { fatalError("Internal Auth Error: missing token in EmailLinkSignInResponse") @@ -1484,7 +1489,7 @@ extension User: NSSecureCoding {} #if !os(watchOS) private func link(withGameCenterCredential gameCenterCredential: GameCenterAuthCredential, completion: ((AuthDataResult?, Error?) -> Void)?) { - internalGetToken { accessToken, error in + internalGetToken(backend: backend) { accessToken, error in guard let requestConfiguration = self.auth?.requestConfiguration, let publicKeyURL = gameCenterCredential.publicKeyURL, let signature = gameCenterCredential.signature, @@ -1503,7 +1508,7 @@ extension User: NSSecureCoding {} request.accessToken = accessToken Task { do { - let response = try await AuthBackend.call(with: request) + let response = try await self.backend.call(with: request) guard let idToken = response.idToken, let refreshToken = response.refreshToken else { fatalError("Internal Auth Error: missing token in link(withGameCredential") @@ -1584,10 +1589,11 @@ extension User: NSSecureCoding {} /// - Parameter callback: The block to invoke when the token is available. Invoked asynchronously /// on the global work thread in the future. func internalGetToken(forceRefresh: Bool = false, + backend: AuthBackend, callback: @escaping (String?, Error?) -> Void) { Task { do { - let token = try await internalGetTokenAsync(forceRefresh: forceRefresh) + let token = try await internalGetTokenAsync(forceRefresh: forceRefresh, backend: backend) callback(token, nil) } catch { callback(nil, error) @@ -1597,11 +1603,12 @@ extension User: NSSecureCoding {} /// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. /// - Parameter forceRefresh - func internalGetTokenAsync(forceRefresh: Bool = false) async throws -> String { + func internalGetTokenAsync(forceRefresh: Bool = false, + backend: AuthBackend) async throws -> String { var keychainError = false do { let (token, tokenUpdated) = try await tokenService.fetchAccessToken( - forcingRefresh: forceRefresh + forcingRefresh: forceRefresh, backend: backend ) if tokenUpdated { if let error = updateKeychain() { @@ -1756,6 +1763,10 @@ extension User: NSSecureCoding {} ) as? String requestConfiguration = AuthRequestConfiguration(apiKey: apiKey ?? "", appID: appID ?? "") + // This property will be overwritten later via the `user.auth` property update. For now, a + // placeholder is set as the property update should happen right after this intializer. + backend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer()) + userProfileUpdate = UserProfileUpdate() #if os(iOS) self.multiFactor = multiFactor ?? MultiFactor() diff --git a/FirebaseAuth/Sources/Swift/User/UserProfileUpdate.swift b/FirebaseAuth/Sources/Swift/User/UserProfileUpdate.swift index 74aa5cf5c73..0c51eb9fe83 100644 --- a/FirebaseAuth/Sources/Swift/User/UserProfileUpdate.swift +++ b/FirebaseAuth/Sources/Swift/User/UserProfileUpdate.swift @@ -18,13 +18,13 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) actor UserProfileUpdate { func link(user: User, with credential: AuthCredential) async throws -> AuthDataResult { - let accessToken = try await user.internalGetTokenAsync() + let accessToken = try await user.internalGetTokenAsync(backend: user.backend) let request = VerifyAssertionRequest(providerID: credential.provider, requestConfiguration: user.requestConfiguration) credential.prepare(request) request.accessToken = accessToken do { - let response = try await AuthBackend.call(with: request) + let response = try await user.backend.call(with: request) guard let idToken = response.idToken, let refreshToken = response.refreshToken, let providerID = response.providerID else { @@ -48,7 +48,7 @@ actor UserProfileUpdate { } func unlink(user: User, fromProvider provider: String) async throws -> User { - let accessToken = try await user.internalGetTokenAsync() + let accessToken = try await user.internalGetTokenAsync(backend: user.backend) let request = SetAccountInfoRequest( accessToken: accessToken, requestConfiguration: user.requestConfiguration ) @@ -58,7 +58,7 @@ actor UserProfileUpdate { } request.deleteProviders = [provider] do { - let response = try await AuthBackend.call(with: request) + let response = try await user.backend.call(with: request) // We can't just use the provider info objects in SetAccountInfoResponse // because they don't have localID and email fields. Remove the specific @@ -105,7 +105,7 @@ actor UserProfileUpdate { SetAccountInfoRequest) -> Void) async throws { let userAccountInfo = try await getAccountInfoRefreshingCache(user) - let accessToken = try await user.internalGetTokenAsync() + let accessToken = try await user.internalGetTokenAsync(backend: user.backend) // Mutate setAccountInfoRequest in block let setAccountInfoRequest = @@ -115,7 +115,7 @@ actor UserProfileUpdate { ) changeBlock(userAccountInfo, setAccountInfoRequest) do { - let accountInfoResponse = try await AuthBackend.call(with: setAccountInfoRequest) + let accountInfoResponse = try await user.backend.call(with: setAccountInfoRequest) if let idToken = accountInfoResponse.idToken, let refreshToken = accountInfoResponse.refreshToken { let tokenService = SecureTokenService( @@ -143,13 +143,13 @@ actor UserProfileUpdate { accessTokenExpirationDate: expirationDate, refreshToken: refreshToken ) - let accessToken = try await user.internalGetTokenAsync() + let accessToken = try await user.internalGetTokenAsync(backend: user.backend) let getAccountInfoRequest = GetAccountInfoRequest( accessToken: accessToken, requestConfiguration: user.requestConfiguration ) do { - let response = try await AuthBackend.call(with: getAccountInfoRequest) + let response = try await user.backend.call(with: getAccountInfoRequest) user.isAnonymous = false user.update(withGetAccountInfoResponse: response) } catch { @@ -168,7 +168,7 @@ actor UserProfileUpdate { /// - Parameter tokenService: The new token service object. /// - Parameter callback: The block to be called in the global auth working queue once finished. func setTokenService(user: User, tokenService: SecureTokenService) async throws { - _ = try await tokenService.fetchAccessToken(forcingRefresh: false) + _ = try await tokenService.fetchAccessToken(forcingRefresh: false, backend: user.backend) user.tokenService = tokenService if let error = user.updateKeychain() { throw error @@ -180,11 +180,11 @@ actor UserProfileUpdate { /// error has been detected. Invoked asynchronously on the auth global work queue in the future. func getAccountInfoRefreshingCache(_ user: User) async throws -> GetAccountInfoResponse.User { - let token = try await user.internalGetTokenAsync() + let token = try await user.internalGetTokenAsync(backend: user.backend) let request = GetAccountInfoRequest(accessToken: token, requestConfiguration: user.requestConfiguration) do { - let accountInfoResponse = try await AuthBackend.call(with: request) + let accountInfoResponse = try await user.backend.call(with: request) user.update(withGetAccountInfoResponse: accountInfoResponse) if let error = user.updateKeychain() { throw error diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index 6919ac40807..d4247bd6c31 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -149,12 +149,12 @@ } } - guard let requestConfiguration = auth?.requestConfiguration else { + guard let auth = auth else { throw AuthErrorUtils.error(code: .recaptchaNotEnabled, message: "No requestConfiguration for Auth instance") } - let request = GetRecaptchaConfigRequest(requestConfiguration: requestConfiguration) - let response = try await AuthBackend.call(with: request) + let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration) + let response = try await auth.backend.call(with: request) AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.") // Response's site key is of the format projects//keys/' guard let keys = response.recaptchaKey?.components(separatedBy: "/"), @@ -179,7 +179,7 @@ } let config = AuthRecaptchaConfig(siteKey: siteKey, enablementStatus: enablementStatus) - if let tenantID = auth?.tenantID { + if let tenantID = auth.tenantID { tenantConfigs[tenantID] = config } else { agentConfig = config diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthWebUtils.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthWebUtils.swift index 2231c040023..69210b9326b 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthWebUtils.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthWebUtils.swift @@ -98,7 +98,8 @@ class AuthWebUtils { return urlComponents.first } - static func fetchAuthDomain(withRequestConfiguration requestConfiguration: AuthRequestConfiguration) + static func fetchAuthDomain(withRequestConfiguration requestConfiguration: AuthRequestConfiguration, + backend: AuthBackend) async throws -> String { if let emulatorHostAndPort = requestConfiguration.emulatorHostAndPort { // If we are using the auth emulator, we do not want to call the GetProjectConfig endpoint. @@ -107,7 +108,7 @@ class AuthWebUtils { } let request = GetProjectConfigRequest(requestConfiguration: requestConfiguration) - let response = try await AuthBackend.call(with: request) + let response = try await backend.call(with: request) // Look up an authorized domain ends with one of the supportedAuthDomains. // The sequence of supportedAuthDomains matters. ("firebaseapp.com", "web.app") diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift index fdde2e0757d..e9567a69e9d 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift @@ -481,7 +481,7 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { Task { do { - let verifyResponse = try await AuthBackend.call(with: request) + let verifyResponse = try await AppManager.shared.auth().backend.call(with: request) guard let receipt = verifyResponse.receipt, let timeoutDate = verifyResponse.suggestedTimeOutDate else { @@ -510,7 +510,7 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { ) do { - _ = try await AuthBackend.call(with: request) + _ = try await AppManager.shared.auth().backend.call(with: request) print("Verify iOS client succeeded") } catch { print("Verify iOS Client failed: \(error.localizedDescription)") diff --git a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift index a7a484a7d5d..5feaf239e3b 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift @@ -41,7 +41,7 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withEncodingError: encodingError) do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -71,7 +71,7 @@ class AuthBackendTests: RPCBaseTests { func testBodyDataSerializationError() async throws { let request = FakeRequest(withRequestBody: ["unencodable": self]) do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -99,7 +99,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(withData: nil, error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -131,7 +131,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(withData: data, error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -168,7 +168,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(withData: data, error: nil) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -210,7 +210,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(withData: data, error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -252,7 +252,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(withData: data, error: nil) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -287,7 +287,7 @@ class AuthBackendTests: RPCBaseTests { error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -329,7 +329,7 @@ class AuthBackendTests: RPCBaseTests { ) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -356,7 +356,7 @@ class AuthBackendTests: RPCBaseTests { error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -398,7 +398,7 @@ class AuthBackendTests: RPCBaseTests { error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -436,7 +436,7 @@ class AuthBackendTests: RPCBaseTests { let _ = try self.rpcIssuer.respond(withJSON: [:], error: responseError) } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -473,7 +473,7 @@ class AuthBackendTests: RPCBaseTests { try self.rpcIssuer.respond(serverErrorMessage: customErrorMessage, error: responseError) } do { - let _ = try await AuthBackend.call(with: FakeRequest(withRequestBody: [:])) + let _ = try await authBackend.call(with: FakeRequest(withRequestBody: [:])) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -497,7 +497,7 @@ class AuthBackendTests: RPCBaseTests { } do { let request = FakeDecodingErrorRequest(withRequestBody: [:]) - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Expected to throw") } catch { let rpcError = error as NSError @@ -528,7 +528,7 @@ class AuthBackendTests: RPCBaseTests { // value it was given. try self.rpcIssuer.respond(withJSON: [kTestKey: kTestValue]) } - let rpcResponse = try await AuthBackend.call(with: FakeRequest(withRequestBody: [:])) + let rpcResponse = try await authBackend.call(with: FakeRequest(withRequestBody: [:])) XCTAssertEqual(try XCTUnwrap(rpcResponse.receivedValue), kTestValue) } @@ -593,7 +593,7 @@ class AuthBackendTests: RPCBaseTests { // Force return from async post try self.rpcIssuer.respond(withJSON: [:]) } - _ = try? await AuthBackend.call(with: request) + _ = try? await authBackend.call(with: request) // Then let expectedHeader = HeartbeatLoggingTestUtils.nonEmptyHeartbeatsPayload.headerValue() @@ -620,7 +620,7 @@ class AuthBackendTests: RPCBaseTests { // Just force return from async call. try self.rpcIssuer.respond(withJSON: [:]) } - _ = try? await AuthBackend.call(with: request) + _ = try? await authBackend.call(with: request) let completeRequest = await rpcIssuer.completeRequest.value let headerValue = completeRequest.value(forHTTPHeaderField: "X-Firebase-AppCheck") @@ -650,7 +650,7 @@ class AuthBackendTests: RPCBaseTests { // Force return from async post try self.rpcIssuer.respond(withJSON: [:]) } - _ = try? await AuthBackend.call(with: request) + _ = try? await authBackend.call(with: request) // Then let completeRequest = await rpcIssuer.completeRequest.value @@ -713,7 +713,7 @@ class AuthBackendTests: RPCBaseTests { private struct FakeResponse: AuthRPCResponse { var receivedValue: String? - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { receivedValue = dictionary["TestKey"] as? String } } @@ -739,7 +739,7 @@ class AuthBackendTests: RPCBaseTests { } private struct FakeDecodingErrorResponse: AuthRPCResponse { - mutating func setFields(dictionary: [String: AnyHashable]) throws { + init(dictionary: [String: AnyHashable]) throws { throw NSError(domain: "dummy", code: -1) } } diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index 1167bf22ca2..f84eb33d70f 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -47,7 +47,8 @@ class AuthTests: RPCBaseTests { #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE auth = Auth( app: FirebaseApp.app(name: name)!, - keychainStorageProvider: keychainStorageProvider + keychainStorageProvider: keychainStorageProvider, + backend: authBackend ) // Set authDispatcherCallback implementation in order to save the token refresh task for later diff --git a/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift b/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift index af1f54bce28..334091d21fd 100644 --- a/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift +++ b/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift @@ -75,7 +75,7 @@ class CreateAuthURITests: RPCBaseTests { rpcIssuer?.respondBlock = { try self.rpcIssuer?.respond(withJSON: [kAuthUriKey: kTestAuthUri]) } - let rpcResponse = try await AuthBackend.call(with: makeAuthURIRequest()) + let rpcResponse = try await authBackend.call(with: makeAuthURIRequest()) XCTAssertEqual(rpcResponse.authURI, kTestAuthUri) } @@ -89,7 +89,7 @@ class CreateAuthURITests: RPCBaseTests { .respond(withJSON: ["kind": kTestExpectedKind, "allProviders": [kTestProviderID1, kTestProviderID2]]) } - let rpcResponse = try await AuthBackend.call(with: makeAuthURIRequest()) + let rpcResponse = try await authBackend.call(with: makeAuthURIRequest()) XCTAssertEqual(rpcIssuer?.requestURL?.absoluteString, kExpectedAPIURL) XCTAssertEqual(rpcIssuer?.decodedRequest?["identifier"] as? String, kTestIdentifier) diff --git a/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift b/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift index ae213aa8464..a968a02e3e8 100644 --- a/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift +++ b/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift @@ -64,7 +64,7 @@ class DeleteAccountTests: RPCBaseTests { rpcIssuer?.respondBlock = { try self.rpcIssuer?.respond(withJSON: [:]) } - let rpcResponse = try await AuthBackend.call(with: makeDeleteAccountRequest()) + let rpcResponse = try await authBackend.call(with: makeDeleteAccountRequest()) XCTAssertNotNil(rpcResponse) } diff --git a/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift b/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift index 2cdd4943653..ce4b2dd57d5 100644 --- a/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift +++ b/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift @@ -65,7 +65,7 @@ class EmailLinkSignInTests: RPCBaseTests { XCTAssertNil(requestDictionary[self.kIDTokenKey]) try self.rpcIssuer?.respond(withJSON: [:]) // unblock the await } - let _ = try await AuthBackend.call(with: makeEmailLinkSignInRequest()) + let _ = try await authBackend.call(with: makeEmailLinkSignInRequest()) } /** @fn testEmailLinkRequestCreationOptional @@ -87,7 +87,7 @@ class EmailLinkSignInTests: RPCBaseTests { XCTAssertEqual(requestDictionary[self.kIDTokenKey], kTestIDToken) try self.rpcIssuer?.respond(withJSON: [:]) // unblock the await } - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) } func testEmailLinkSignInErrors() async throws { @@ -115,7 +115,7 @@ class EmailLinkSignInTests: RPCBaseTests { "expiresIn": "\(kTestTokenExpirationTimeInterval)", "refreshToken": kTestRefreshToken]) } - let response = try await AuthBackend.call(with: makeEmailLinkSignInRequest()) + let response = try await authBackend.call(with: makeEmailLinkSignInRequest()) XCTAssertEqual(response.idToken, kTestIDTokenResponse) XCTAssertEqual(response.email, kTestEmailResponse) diff --git a/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift b/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift index 87a294c0ef2..dff1e74936e 100644 --- a/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift +++ b/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift @@ -100,7 +100,7 @@ class GetAccountInfoTests: RPCBaseTests { rpcIssuer?.respondBlock = { try self.rpcIssuer?.respond(withJSON: ["users": usersIn]) } - let rpcResponse = try await AuthBackend.call(with: makeGetAccountInfoRequest()) + let rpcResponse = try await authBackend.call(with: makeGetAccountInfoRequest()) let users = try XCTUnwrap(rpcResponse.users) XCTAssertGreaterThan(users.count, 0) diff --git a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift index b9fe798f57d..631bab3a723 100644 --- a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift +++ b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift @@ -199,7 +199,7 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { rpcIssuer?.respondBlock = { try self.rpcIssuer?.respond(withJSON: [self.kOOBCodeKey: self.kTestOOBCode]) } - let response = try await AuthBackend.call(with: request()) + let response = try await authBackend.call(with: request()) XCTAssertEqual(response.OOBCode, kTestOOBCode) } } @@ -217,7 +217,7 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { rpcIssuer?.respondBlock = { try self.rpcIssuer?.respond(withJSON: [:]) } - let response = try await AuthBackend.call(with: request()) + let response = try await authBackend.call(with: request()) XCTAssertNil(response.OOBCode) } } diff --git a/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift b/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift index 107a5c33b4f..6dbe4c644c6 100644 --- a/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift +++ b/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift @@ -60,7 +60,7 @@ class GetProjectConfigTests: RPCBaseTests { try self.rpcIssuer?.respond(withJSON: ["projectId": kTestProjectID, "authorizedDomains": [kTestDomain1, kTestDomain2]]) } - let rpcResponse = try await AuthBackend.call(with: makeGetProjectConfigRequest()) + let rpcResponse = try await authBackend.call(with: makeGetProjectConfigRequest()) XCTAssertEqual(rpcResponse.projectID, kTestProjectID) XCTAssertEqual(rpcResponse.authorizedDomains?.first, kTestDomain1) XCTAssertEqual(rpcResponse.authorizedDomains?[1], kTestDomain2) diff --git a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift index df64689c7c0..75149c38d45 100644 --- a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift +++ b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift @@ -24,7 +24,7 @@ class GetRecaptchaConfigTests: RPCBaseTests { */ func testGetRecaptchaConfigRequest() async throws { let request = GetRecaptchaConfigRequest(requestConfiguration: makeRequestConfiguration()) - // let _ = try await AuthBackend.call(with: request) + // let _ = try await authBackend.call(with: request) XCTAssertFalse(request.containsPostBody) // Confirm that the request has no decoded body as it is get request. @@ -47,7 +47,7 @@ class GetRecaptchaConfigTests: RPCBaseTests { let request = GetRecaptchaConfigRequest(requestConfiguration: makeRequestConfiguration()) rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey - let response = try await AuthBackend.call(with: request) + let response = try await authBackend.call(with: request) XCTAssertEqual(response.recaptchaKey, kTestRecaptchaKey) XCTAssertNil(response.enforcementState) } diff --git a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift index 6f1ed895b0a..a5a330babf7 100644 --- a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift @@ -282,6 +282,10 @@ import FirebaseCore .replacingOccurrences(of: ")", with: "") FirebaseApp.configure(name: strippedName, options: options) OAuthProviderTests.auth = Auth.auth(app: FirebaseApp.app(name: strippedName)!) + OAuthProviderTests.auth = Auth( + app: FirebaseApp.app(name: strippedName)!, + backend: authBackend + ) OAuthProviderTests.auth?.mainBundleUrlTypes = [["CFBundleURLSchemes": [scheme]]] } diff --git a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift index 0030c52776d..9a319ea9755 100644 --- a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift @@ -662,7 +662,7 @@ let strippedName = functionName.replacingOccurrences(of: "(", with: "") .replacingOccurrences(of: ")", with: "") FirebaseApp.configure(name: strippedName, options: options) - let auth = Auth.auth(app: FirebaseApp.app(name: strippedName)!) + let auth = Auth(app: FirebaseApp.app(name: strippedName)!, backend: authBackend) kAuthGlobalWorkQueue.sync { // Wait for Auth protectedDataInitialization to finish. diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 009289a1b44..9a8f9026ea9 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -68,15 +68,16 @@ class RPCBaseTests: XCTestCase { let kTestIdentifier = "Identifier" var rpcIssuer: FakeBackendRPCIssuer! + var authBackend: AuthBackend! override func setUp() { rpcIssuer = FakeBackendRPCIssuer() - AuthBackend.setTestRPCIssuer(issuer: rpcIssuer) + authBackend = AuthBackend(rpcIssuer: rpcIssuer) } override func tearDown() { rpcIssuer = nil - AuthBackend.resetRPCIssuer() + authBackend = nil } /** @fn checkRequest @@ -99,7 +100,7 @@ class RPCBaseTests: XCTestCase { // Dummy response to unblock await. let _ = try self.rpcIssuer?.respond(withJSON: [:]) } - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) } /** @fn checkBackendError @@ -123,7 +124,7 @@ class RPCBaseTests: XCTestCase { } } do { - let _ = try await AuthBackend.call(with: request) + let _ = try await authBackend.call(with: request) XCTFail("Did not throw expected error") return } catch { diff --git a/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift b/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift index 7fd7f346d3d..a3220f3ee41 100644 --- a/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift +++ b/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift @@ -82,7 +82,7 @@ class ResetPasswordTests: RPCBaseTests { try self.rpcIssuer?.respond(withJSON: ["email": kTestEmail, "requestType": kExpectedResetPasswordRequestType]) } - let rpcResponse = try await AuthBackend.call(with: makeResetPasswordRequest()) + let rpcResponse = try await authBackend.call(with: makeResetPasswordRequest()) XCTAssertEqual(rpcResponse.email, kTestEmail) XCTAssertEqual(rpcResponse.requestType, kExpectedResetPasswordRequestType) diff --git a/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift b/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift index 945e1e1ee1b..f55f42514d7 100644 --- a/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift +++ b/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift @@ -53,7 +53,7 @@ class RevokeTokenTests: RPCBaseTests { rpcIssuer.respondBlock = { try self.rpcIssuer?.respond(withJSON: [:]) } - let rpcResponse = try await AuthBackend.call(with: makeRevokeTokenRequest()) + let rpcResponse = try await authBackend.call(with: makeRevokeTokenRequest()) XCTAssertNotNil(rpcResponse) } diff --git a/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift b/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift index aa5a30686b6..d6b4b42bc14 100644 --- a/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift +++ b/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift @@ -113,7 +113,7 @@ class SendVerificationCodeTests: RPCBaseTests { rpcIssuer.respondBlock = { try self.rpcIssuer?.respond(withJSON: [kVerificationIDKey: kFakeVerificationID]) } - let rpcResponse = try await AuthBackend.call(with: + let rpcResponse = try await authBackend.call(with: makeSendVerificationCodeRequest(CodeIdentity.recaptcha(kTestReCAPTCHAToken))) XCTAssertNotNil(rpcResponse) XCTAssertEqual(rpcResponse.verificationID, kFakeVerificationID) diff --git a/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift b/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift index 4efe951991a..037116982de 100644 --- a/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift +++ b/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift @@ -212,7 +212,7 @@ class SetAccountInfoTests: RPCBaseTests { kExpiresInKey: kTestExpiresIn, kRefreshTokenKey: kTestRefreshToken]) } - let response = try await AuthBackend.call(with: setAccountInfoRequest()) + let response = try await authBackend.call(with: setAccountInfoRequest()) XCTAssertEqual(response.providerUserInfo?.first?.photoURL?.absoluteString, kTestPhotoURL) XCTAssertEqual(response.idToken, kTestIDToken) XCTAssertEqual(response.refreshToken, kTestRefreshToken) diff --git a/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift b/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift index 3513e9212c8..515cbd13e87 100644 --- a/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift +++ b/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift @@ -99,7 +99,7 @@ class SignInWithGameCenterTests: RPCBaseTests { "displayName": kDisplayName, ]) } - let rpcResponse = try await AuthBackend.call(with: request) + let rpcResponse = try await authBackend.call(with: request) XCTAssertNotNil(rpcResponse) XCTAssertEqual(rpcResponse.idToken, kIDToken) diff --git a/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift b/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift index 74c271bff6e..a75f6263a79 100644 --- a/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift +++ b/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift @@ -82,7 +82,7 @@ class SignUpNewUserTests: RPCBaseTests { kRefreshTokenKey: kTestRefreshToken, ]) } - let rpcResponse = try await AuthBackend.call(with: makeSignUpNewUserRequest()) + let rpcResponse = try await authBackend.call(with: makeSignUpNewUserRequest()) XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken) let expiresIn = try XCTUnwrap(rpcResponse.approximateExpirationDate?.timeIntervalSinceNow) XCTAssertEqual(expiresIn, 12345, accuracy: 0.1) diff --git a/FirebaseAuth/Tests/Unit/UserTests.swift b/FirebaseAuth/Tests/Unit/UserTests.swift index 77c1449792f..d1f305f7116 100644 --- a/FirebaseAuth/Tests/Unit/UserTests.swift +++ b/FirebaseAuth/Tests/Unit/UserTests.swift @@ -33,12 +33,13 @@ class UserTests: RPCBaseTests { let kVerificationID = "55432" let kPhoneNumber = "555-1234" - static var auth: Auth? + var auth: Auth? - override class func setUp() { + override func setUp() { + super.setUp() let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000", gcmSenderID: "00000000000000000-00000000000-000000000") - options.apiKey = kFakeAPIKey + options.apiKey = Self.kFakeAPIKey options.projectID = "myUserProjectID" FirebaseApp.configure(name: "test-UserTests", options: options) #if (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE @@ -48,13 +49,17 @@ class UserTests: RPCBaseTests { #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE auth = Auth( app: FirebaseApp.app(name: "test-UserTests")!, - keychainStorageProvider: keychainStorageProvider + keychainStorageProvider: keychainStorageProvider, + backend: authBackend ) } override func tearDown() { // Verifies that no tasks are left suspended on the AuthSerialTaskQueue. - try? UserTests.auth?.signOut() + try? auth?.signOut() + auth = nil + FirebaseApp.resetApps() + super.tearDown() } /** @fn testUserPropertiesAndNSSecureCoding @@ -415,7 +420,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -441,7 +446,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is no longer signed in.. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -457,7 +462,7 @@ class UserTests: RPCBaseTests { func testUpdatePhoneSuccess() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { @@ -491,7 +496,7 @@ class UserTests: RPCBaseTests { func testUpdatePhoneNumberFailure() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { @@ -523,7 +528,7 @@ class UserTests: RPCBaseTests { func testUpdatePhoneNumberFailureAutoSignOut() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { @@ -540,7 +545,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue) // User is no longer signed in. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -579,7 +584,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -605,7 +610,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -632,7 +637,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is signed out. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -688,7 +693,7 @@ class UserTests: RPCBaseTests { XCTAssertEqual(user.email, self.kEmail) XCTAssertEqual(user.displayName, self.kDisplayName) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -716,7 +721,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is signed out. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -821,7 +826,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.quotaExceeded.rawValue) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -848,7 +853,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue) // User is no longer signed in. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -878,7 +883,7 @@ class UserTests: RPCBaseTests { XCTAssertEqual(result.user.email, user.email) XCTAssertEqual(result.additionalUserInfo?.isNewUser, false) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -914,7 +919,7 @@ class UserTests: RPCBaseTests { } XCTAssertNil(error) // Verify that the current user is unchanged. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) // Verify that the current user and reauthenticated user are not same pointers. XCTAssertNotEqual(user, reauthenticatedAuthResult?.user) // Verify that anyway the current user and reauthenticated user have same IDs. @@ -933,7 +938,7 @@ class UserTests: RPCBaseTests { } } waitForExpectations(timeout: 5) - try assertUserGoogle(UserTests.auth?.currentUser) + try assertUserGoogle(auth?.currentUser) } /** @fn testReauthenticateFailure @@ -958,7 +963,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -987,7 +992,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1001,7 +1006,7 @@ class UserTests: RPCBaseTests { func testLinkAndRetrieveDataSuccess() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithFacebookCredential { user in XCTAssertNotNil(user) do { @@ -1069,7 +1074,7 @@ class UserTests: RPCBaseTests { // Email should not have changed on the client side. XCTAssertEqual(user.email, self.kFacebookEmail) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1100,7 +1105,7 @@ class UserTests: RPCBaseTests { XCTFail("Expected to throw providerAlreadyLinked error.") } // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1130,7 +1135,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userDisabled.rawValue) // User is signed out. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -1145,7 +1150,7 @@ class UserTests: RPCBaseTests { func testLinkEmailAndRetrieveDataSuccess() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithFacebookCredential { user in XCTAssertNotNil(user) do { @@ -1213,7 +1218,7 @@ class UserTests: RPCBaseTests { XCTFail("Expected to throw providerAlreadyLinked error.") } // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1247,7 +1252,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.tooManyRequests.rawValue) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1277,7 +1282,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue) // User is signed out. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -1307,7 +1312,7 @@ class UserTests: RPCBaseTests { func testLinkProviderFailure() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithFacebookCredential { user in XCTAssertNotNil(user) do { @@ -1322,7 +1327,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue) // User is signed out. - XCTAssertNil(UserTests.auth?.currentUser) + XCTAssertNil(self.auth?.currentUser) expectation.fulfill() } } @@ -1336,7 +1341,7 @@ class UserTests: RPCBaseTests { func testReauthenticateWithProviderFailure() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithFacebookCredential { user in XCTAssertNotNil(user) do { @@ -1351,7 +1356,7 @@ class UserTests: RPCBaseTests { let error = try! XCTUnwrap(rawError) XCTAssertEqual((error as NSError).code, AuthErrorCode.userTokenExpired.rawValue) // User is still signed in. - XCTAssertEqual(UserTests.auth?.currentUser, user) + XCTAssertEqual(self.auth?.currentUser, user) expectation.fulfill() } } @@ -1365,7 +1370,7 @@ class UserTests: RPCBaseTests { func testLinkPhoneAuthCredentialSuccess() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in XCTAssertNotNil(user) self.expectVerifyPhoneNumberRequest(isLink: true) @@ -1410,7 +1415,7 @@ class UserTests: RPCBaseTests { func testUnlinkPhoneAuthCredentialSuccess() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in XCTAssertNotNil(user) self.expectVerifyPhoneNumberRequest(isLink: true) @@ -1506,7 +1511,7 @@ class UserTests: RPCBaseTests { func testlinkPhoneCredentialAlreadyExistsError() throws { setFakeGetAccountProvider() let expectation = self.expectation(description: #function) - let auth = try XCTUnwrap(UserTests.auth) + let auth = try XCTUnwrap(self.auth) signInWithEmailPasswordReturnFakeUser { user in XCTAssertNotNil(user) self.expectVerifyPhoneNumberRequest(isLink: true) @@ -1668,12 +1673,12 @@ class UserTests: RPCBaseTests { } // 1. After setting up fakes, sign out and sign in. do { - try UserTests.auth?.signOut() + try auth?.signOut() } catch { XCTFail("Sign out failed: \(error)") return } - UserTests.auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in + auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in // 4. After the response triggers the callback, verify the returned result. XCTAssertTrue(Thread.isMainThread) guard let user = authResult?.user else { @@ -1716,10 +1721,10 @@ class UserTests: RPCBaseTests { } do { - try UserTests.auth?.signOut() + try auth?.signOut() let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken, accessToken: kGoogleAccessToken) - UserTests.auth?.signIn(with: googleCredential) { authResult, error in + auth?.signIn(with: googleCredential) { authResult, error in // 4. After the response triggers the callback, verify the returned result. XCTAssertTrue(Thread.isMainThread) guard let user = authResult?.user else { @@ -1783,10 +1788,10 @@ class UserTests: RPCBaseTests { } do { - try UserTests.auth?.signOut() + try auth?.signOut() let facebookCredential = FacebookAuthProvider .credential(withAccessToken: kFacebookAccessToken) - UserTests.auth?.signIn(with: facebookCredential) { authResult, error in + auth?.signIn(with: facebookCredential) { authResult, error in // 4. After the response triggers the callback, verify the returned result. XCTAssertTrue(Thread.isMainThread) guard let user = authResult?.user else { @@ -1838,8 +1843,8 @@ class UserTests: RPCBaseTests { } do { - try UserTests.auth?.signOut() - UserTests.auth?.signIn( + try auth?.signOut() + auth?.signIn( withEmail: kEmail, link: "https://www.google.com?oobCode=aCode&mode=signIn" ) { authResult, error in diff --git a/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift b/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift index 95e131a8760..2fb630a62ce 100644 --- a/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift @@ -180,7 +180,7 @@ class VerifyAssertionTests: RPCBaseTests { self.kRawUserInfoKey: self.profile, ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyAssertionRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyAssertionRequest()) XCTAssertEqual(rpcResponse.idToken, kTestIDToken) XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken) XCTAssertEqual(rpcResponse.verifiedProvider, [kTestProvider]) @@ -211,7 +211,7 @@ class VerifyAssertionTests: RPCBaseTests { self.kRawUserInfoKey: self.convertToJson(self.profile), ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyAssertionRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyAssertionRequest()) XCTAssertEqual(rpcResponse.idToken, kTestIDToken) XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken) XCTAssertEqual(rpcResponse.verifiedProvider, [kTestProvider]) diff --git a/FirebaseAuth/Tests/Unit/VerifyClientTests.swift b/FirebaseAuth/Tests/Unit/VerifyClientTests.swift index 0f7b0c792ca..528cb357c88 100644 --- a/FirebaseAuth/Tests/Unit/VerifyClientTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyClientTests.swift @@ -71,7 +71,7 @@ class VerifyClientTests: RPCBaseTests { kSuggestedTimeOutKey: kFakeSuggestedTimeout, ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyClientRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyClientRequest()) XCTAssertEqual(rpcResponse.receipt, kFakeReceipt) let timeOut = try XCTUnwrap(rpcResponse.suggestedTimeOutDate?.timeIntervalSinceNow) XCTAssertEqual(timeOut, 1234, accuracy: 0.1) diff --git a/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift b/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift index 36fb06d13e6..8e3e052a4b2 100644 --- a/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift @@ -107,7 +107,7 @@ class VerifyCustomTokenTests: RPCBaseTests { kIsNewUserKey: true, ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyCustomTokenRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyCustomTokenRequest()) XCTAssertEqual(rpcResponse.idToken, kTestIDToken) XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken) let expiresIn = try XCTUnwrap(rpcResponse.approximateExpirationDate?.timeIntervalSinceNow) diff --git a/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift b/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift index 6b831f0ce80..06821bf74c2 100644 --- a/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift @@ -171,7 +171,7 @@ class VerifyPasswordTests: RPCBaseTests { kPhotoUrlKey: kTestPhotoUrl, ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyPasswordRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyPasswordRequest()) XCTAssertEqual(rpcResponse.email, kTestEmail) XCTAssertEqual(rpcResponse.localID, kTestLocalID) XCTAssertEqual(rpcResponse.displayName, kTestDisplayName) diff --git a/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift b/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift index e6ff2a42434..50fb9cf67e5 100644 --- a/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift @@ -116,7 +116,7 @@ import XCTest "isNewUser": true, ]) } - let rpcResponse = try await AuthBackend.call(with: makeVerifyPhoneNumberRequest()) + let rpcResponse = try await authBackend.call(with: makeVerifyPhoneNumberRequest()) XCTAssertEqual(rpcResponse.localID, kTestLocalID) XCTAssertEqual(rpcResponse.idToken, kTestIDToken) let expiresIn = try XCTUnwrap(rpcResponse.approximateExpirationDate?.timeIntervalSinceNow) @@ -135,7 +135,7 @@ import XCTest ]) } do { - let _ = try await AuthBackend.call(with: makeVerifyPhoneNumberRequestWithTemporaryProof()) + let _ = try await authBackend.call(with: makeVerifyPhoneNumberRequestWithTemporaryProof()) XCTFail("Expected to throw") } catch { let rpcError = error as NSError From 6ecea259ecebbcfb8c488ca91339f6ee6a7fef2b Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:02:46 -0500 Subject: [PATCH 25/98] [Auth] Mark *Credential classes as Sendable (#14100) --- FirebaseAuth/Sources/Swift/AuthProvider/AuthCredential.swift | 2 +- .../Sources/Swift/AuthProvider/EmailAuthProvider.swift | 3 ++- .../Sources/Swift/AuthProvider/FacebookAuthProvider.swift | 3 ++- .../Sources/Swift/AuthProvider/GameCenterAuthProvider.swift | 2 +- .../Sources/Swift/AuthProvider/GitHubAuthProvider.swift | 3 ++- .../Sources/Swift/AuthProvider/GoogleAuthProvider.swift | 3 ++- FirebaseAuth/Sources/Swift/AuthProvider/OAuthCredential.swift | 3 ++- .../Sources/Swift/AuthProvider/PhoneAuthCredential.swift | 3 ++- .../Sources/Swift/AuthProvider/TwitterAuthProvider.swift | 3 ++- .../Sources/Swift/Utilities/AuthRecaptchaVerifier.swift | 2 +- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/AuthCredential.swift b/FirebaseAuth/Sources/Swift/AuthProvider/AuthCredential.swift index 0500875b10f..2ae683ae22b 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/AuthCredential.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/AuthCredential.swift @@ -16,7 +16,7 @@ import Foundation /// Public representation of a credential. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRAuthCredential) open class AuthCredential: NSObject { +@objc(FIRAuthCredential) open class AuthCredential: NSObject, @unchecked Sendable { /// The name of the identity provider for the credential. @objc public let provider: String diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/EmailAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/EmailAuthProvider.swift index 050dce30974..e87445b84a2 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/EmailAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/EmailAuthProvider.swift @@ -38,7 +38,8 @@ import Foundation } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIREmailPasswordAuthCredential) class EmailAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIREmailPasswordAuthCredential) class EmailAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { let email: String enum EmailType { diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift index cc89e7b3394..59cb2385425 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift @@ -34,7 +34,8 @@ import Foundation } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRFacebookAuthCredential) class FacebookAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIRFacebookAuthCredential) class FacebookAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { let accessToken: String init(withAccessToken accessToken: String) { diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift index 4560bad9aaf..82836ee81b0 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift @@ -129,7 +129,7 @@ @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRGameCenterAuthCredential) - class GameCenterAuthCredential: AuthCredential, NSSecureCoding { + class GameCenterAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { let playerID: String let teamPlayerID: String? let gamePlayerID: String? diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift index 801e63fa8ee..75b914cbb7a 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift @@ -34,7 +34,8 @@ import Foundation } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRGitHubAuthCredential) class GitHubAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIRGitHubAuthCredential) class GitHubAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { let token: String init(withToken token: String) { diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift index 41f223b25dc..0f41ac69ce3 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift @@ -36,7 +36,8 @@ import Foundation } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRGoogleAuthCredential) class GoogleAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIRGoogleAuthCredential) class GoogleAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { let idToken: String let accessToken: String diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthCredential.swift b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthCredential.swift index 920fd138af4..8029fd6df51 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthCredential.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthCredential.swift @@ -16,7 +16,8 @@ import Foundation /// Internal implementation of `AuthCredential` for generic credentials. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIROAuthCredential) open class OAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIROAuthCredential) open class OAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { /// The ID Token associated with this credential. @objc(IDToken) public let idToken: String? diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthCredential.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthCredential.swift index 49f643a34d1..a930fadc2eb 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthCredential.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthCredential.swift @@ -18,7 +18,8 @@ import Foundation /// /// This class is available on iOS only. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRPhoneAuthCredential) open class PhoneAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIRPhoneAuthCredential) open class PhoneAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { enum CredentialKind { case phoneNumber(_ phoneNumber: String, _ temporaryProof: String) case verification(_ id: String, _ code: String) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift index 6364241188f..f9c32f9d5ad 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift @@ -35,7 +35,8 @@ import Foundation } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -@objc(FIRTwitterAuthCredential) class TwitterAuthCredential: AuthCredential, NSSecureCoding { +@objc(FIRTwitterAuthCredential) class TwitterAuthCredential: AuthCredential, NSSecureCoding, + @unchecked Sendable { let token: String let secret: String diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index d4247bd6c31..859496fac82 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -44,7 +44,7 @@ } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) - class AuthRecaptchaVerifier { + class AuthRecaptchaVerifier: @unchecked Sendable { private(set) weak var auth: Auth? private(set) var agentConfig: AuthRecaptchaConfig? private(set) var tenantConfigs: [String: AuthRecaptchaConfig] = [:] From 2b10cabacfc4330174662796f93813589444a78e Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 12 Nov 2024 17:17:23 -0500 Subject: [PATCH 26/98] [Release] Carthage updates for M156 / 11.5.0 (#14103) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + .../FirebaseAnalyticsOnDeviceConversionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + .../CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json | 4 +++- 20 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index f20a644d7d8..b43f6d31b8d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseABTesting-0d51fde82d49f9e8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseABTesting-2233510ff87da3b6.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseABTesting-4d0b187af6fd8d67.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseABTesting-0c318b2c019b4484.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/ABTesting-d0fdf10c43e985b1.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/ABTesting-d0fdf10c43e985b1.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/ABTesting-a71d17cadc209af9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json index 23252863595..892b10e4152 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/Google-Mobile-Ads-SDK-4f24527af297e7f1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/Google-Mobile-Ads-SDK-80ba4cb995505158.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/Google-Mobile-Ads-SDK-3df614a58e6a5fa6.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/Google-Mobile-Ads-SDK-34abc42769a452ec.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/AdMob-8a654a42c33bbcc8.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/AdMob-63dab3b525b94cd9.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/AdMob-134752c6180a2a41.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index 7d6c0b1d9c6..6eef13dc1a5 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalytics-a93a6c81da535385.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalytics-fd2c71a90d62b88a.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalytics-525b465eb296d09e.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAnalytics-7302159af7baa5d6.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Analytics-2468c231ebeb7922.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Analytics-bc8101d420b896c5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Analytics-d2b6a6b0242db786.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json index 18dfed2db67..c1494a9cf81 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAnalyticsOnDeviceConversion-09d94624a2de0ac8.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalyticsOnDeviceConversion-918bc6e0b7a2fd94.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalyticsOnDeviceConversion-1640c514418a23da.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAnalyticsOnDeviceConversion-8f2f37c75bba22f1.zip", "9.0.0": "https://dl.google.com/dl/firebase/ios/carthage/9.0.0/FirebaseAnalyticsOnDeviceConversion-31aedde70a736b8a.zip", "9.1.0": "https://dl.google.com/dl/firebase/ios/carthage/9.1.0/FirebaseAnalyticsOnDeviceConversion-f13b5a47d1e3978d.zip", "9.2.0": "https://dl.google.com/dl/firebase/ios/carthage/9.2.0/FirebaseAnalyticsOnDeviceConversion-2ebf567c4d97de12.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index 2d7321fbe98..ef662dff5d2 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppCheck-d0c5f46e6a2bf4a3.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppCheck-89c39bdcf0bb90fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppCheck-9b0c4a9489968b07.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAppCheck-8b9bb98738bf8bcf.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseAppCheck-9ef1d217cf057203.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseAppCheck-fc03215d9fe45d3a.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseAppCheck-6ebe9e9539f06003.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index 9aca0a85f2b..6610d08d71d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAppDistribution-9b05f4873b275347.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppDistribution-6d2eccaccfd3145f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppDistribution-20ac94ca344af731.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAppDistribution-6d2e83d234fea209.zip", "6.31.0": "https://dl.google.com/dl/firebase/ios/carthage/6.31.0/FirebaseAppDistribution-07f6a2cf7f576a8a.zip", "6.32.0": "https://dl.google.com/dl/firebase/ios/carthage/6.32.0/FirebaseAppDistribution-a9c4f5db794508ca.zip", "6.33.0": "https://dl.google.com/dl/firebase/ios/carthage/6.33.0/FirebaseAppDistribution-448a96d2ade54581.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 36522271aac..4b42255a58b 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseAuth-eade26b5390baf84.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAuth-93dd2965b3f79b98.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAuth-5faf6dc3bb16c732.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAuth-0c8317aa5649f10f.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Auth-0fa76ba0f7956220.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Auth-5ddd2b4351012c7a.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Auth-5e248984d78d7284.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index 7381237c17b..e1e7795e6e5 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseCrashlytics-13851523ad6df088.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseCrashlytics-282a6f3cf3445787.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseCrashlytics-d5c125d6416f6e0a.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseCrashlytics-8b3c9a29b8afd9b3.zip", "6.15.0": "https://dl.google.com/dl/firebase/ios/carthage/6.15.0/FirebaseCrashlytics-1c6d22d5b73c84fd.zip", "6.16.0": "https://dl.google.com/dl/firebase/ios/carthage/6.16.0/FirebaseCrashlytics-938e5fd0e2eab3b3.zip", "6.17.0": "https://dl.google.com/dl/firebase/ios/carthage/6.17.0/FirebaseCrashlytics-fa09f0c8f31ed5d9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 99a776b8c34..6e0f6983421 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDatabase-06dbb1f7d3c8a3e1.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDatabase-38634b55050b94fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDatabase-ed125984da534e96.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseDatabase-c31e803cad22c253.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Database-1f7a820452722c7d.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Database-1f7a820452722c7d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Database-59a12d87456b3e1c.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json index adb21067b99..c4c50f91f6e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseDynamicLinks-e61c61fa80e5ea8a.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDynamicLinks-95f7e222d8456304.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDynamicLinks-f3f9d6cc60c8b832.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseDynamicLinks-2d21fc8dc1ab3b10.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/DynamicLinks-6a76740211df73f5.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/DynamicLinks-6a76740211df73f5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/DynamicLinks-6a76740211df73f5.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index dc4e8e4c326..45a14e7f6e6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFirestore-43af85b854ac842e.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFirestore-e1283f8cd2e0f3ec.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFirestore-f5864e67ddbbc9e8.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseFirestore-7cf86f9ac9b3545c.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Firestore-68fc02c229d0cc69.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Firestore-87a804ab561d91db.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Firestore-ecb3eea7bde7e8e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index 456117effe1..efd2f26058d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseFunctions-307f00117c2efc62.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFunctions-02693a7583303912.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFunctions-8fce8623ed1c6b86.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseFunctions-367ecac87d727ede.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Functions-f4c426016dd41e38.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Functions-c6c44427c3034736.zip", "5.0.0": "https://dl.google.com/dl/firebase/ios/carthage/5.0.0/Functions-146f34c401bd459b.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 8c45cdd1a76..e8fd8e45d64 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/GoogleSignIn-4e8837ef9594b57b.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/GoogleSignIn-8ce1c31ca2236212.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/GoogleSignIn-59eb371d148a2e3a.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/GoogleSignIn-f7dcc2bce87fcb30.zip", "6.0.0": "https://dl.google.com/dl/firebase/ios/carthage/6.0.0/GoogleSignIn-de9c5d5e8eb6d6ea.zip", "6.1.0": "https://dl.google.com/dl/firebase/ios/carthage/6.1.0/GoogleSignIn-8c82f2870573a793.zip", "6.10.0": "https://dl.google.com/dl/firebase/ios/carthage/6.10.0/GoogleSignIn-ff3aef61c4a55b05.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index b7a994f8a62..13d04a0e6ea 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseInAppMessaging-6fae0a778e9d3efa.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseInAppMessaging-3a1a331c86520356.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseInAppMessaging-a8054099dd2918b3.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseInAppMessaging-1264f987e42294c5.zip", "5.10.0": "https://dl.google.com/dl/firebase/ios/carthage/5.10.0/InAppMessaging-a7a3f933362f6e95.zip", "5.11.0": "https://dl.google.com/dl/firebase/ios/carthage/5.11.0/InAppMessaging-fa28ce1b88fbca93.zip", "5.12.0": "https://dl.google.com/dl/firebase/ios/carthage/5.12.0/InAppMessaging-fa28ce1b88fbca93.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 6def9a51b34..93b98c740cd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMLModelDownloader-d8649822e63fbf7f.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMLModelDownloader-517f51af92733a7f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMLModelDownloader-069609cbcde7e789.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseMLModelDownloader-c6340805afa15d66.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseMLModelDownloader-8f972757fb181320.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseMLModelDownloader-058ad59fa6dc0111.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseMLModelDownloader-286479a966d2fb37.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 9bdf4b5b932..02aa108e989 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseMessaging-70e63bb9d9590ded.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMessaging-8a39834fead3c581.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMessaging-2d09725e8b98d199.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseMessaging-984ae5d3101abc86.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Messaging-a22ef2b5f2f30f82.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Messaging-94fa4e090c7e9185.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Messaging-2a00a1c64a19d176.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 666b7238816..ed98e7ed341 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebasePerformance-aa174ee3102722d9.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebasePerformance-a489ac7a27d9b53d.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebasePerformance-9a6f62e80c2324f4.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebasePerformance-28996619a5fdc4b7.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Performance-d8693eb892bfa05b.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Performance-0a400f9460f7a71d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Performance-f5b4002ab96523e4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index f6e8410b08b..e00f9946e4d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseRemoteConfig-9a298869ce3cc6db.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseRemoteConfig-940ed38696414882.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseRemoteConfig-ec432e976582d0eb.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseRemoteConfig-672acb139b4848ef.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/RemoteConfig-7e9635365ccd4a17.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/RemoteConfig-e7928fcb6311c439.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/RemoteConfig-9ab1ca5f360a1780.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 46f2d604ad5..b5a9246e76e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -33,6 +33,7 @@ "11.2.0": "https://dl.google.com/dl/firebase/ios/carthage/11.2.0/FirebaseStorage-b9b969b0d1254065.zip", "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseStorage-0435eeaa87324cd4.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseStorage-0b7a2306152984a2.zip", + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseStorage-a1f0f159f3d7072b.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Storage-6b3e77e1a7fdbc61.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Storage-4721c35d2b90a569.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Storage-821299369b9d0fb2.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json index 0967ef424bc..6f3fcd57470 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json @@ -1 +1,3 @@ -{} +{ + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip" +} From 4ae96849cf1560428df5aaa08350097107a93291 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:23:59 -0500 Subject: [PATCH 27/98] [Auth] Ignore concurrency warnings for global vars made for testing (#14101) --- .../Swift/Backend/IdentityToolkitRequest.swift | 10 +++++++++- .../Swift/Backend/RPC/SecureTokenRequest.swift | 11 +++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift b/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift index 3ee424459a5..3a5d5a3b18a 100644 --- a/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift @@ -19,7 +19,15 @@ private let kHttpProtocol = "http:" private let kEmulatorHostAndPrefixFormat = "%@/%@" -private var gAPIHost = "www.googleapis.com" +#if compiler(>=6) + /// Host for server API calls. This should be changed via + /// `IdentityToolkitRequest.setHost(_ host:)` for testing purposes only. + private nonisolated(unsafe) var gAPIHost = "www.googleapis.com" +#else + /// Host for server API calls. This should be changed via + /// `IdentityToolkitRequest.setHost(_ host:)` for testing purposes only. + private var gAPIHost = "www.googleapis.com" +#endif // compiler(>=6) private let kFirebaseAuthAPIHost = "www.googleapis.com" private let kIdentityPlatformAPIHost = "identitytoolkit.googleapis.com" diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift index e7fa5ee57e5..d11275dcf29 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift @@ -54,8 +54,15 @@ private let kRefreshTokenKey = "refreshToken" /// The key for the "code" parameter in the request. private let kCodeKey = "code" -/// Host for server API calls. -private var gAPIHost = "securetoken.googleapis.com" +#if compiler(>=6) + /// Host for server API calls. This should be changed via + /// `SecureTokenRequest.setHost(_ host:)` for testing purposes only. + private nonisolated(unsafe) var gAPIHost = "securetoken.googleapis.com" +#else + /// Host for server API calls. This should be changed via + /// `SecureTokenRequest.setHost(_ host:)` for testing purposes only. + private var gAPIHost = "securetoken.googleapis.com" +#endif // compiler(>=6) /// Represents the parameters for the token endpoint. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) From c509259bba045b309f8edcd9a5c51f529d599cca Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 12 Nov 2024 19:57:14 -0500 Subject: [PATCH 28/98] [Infra] Use macos-14 for the zip build (#14090) --- .github/workflows/zip.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 1df8854b572..2db3f9d86be 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -30,7 +30,7 @@ jobs: package-release: # Don't run on private repo. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 @@ -58,7 +58,7 @@ jobs: build: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: Xcode 15.2 @@ -75,7 +75,7 @@ jobs: strategy: matrix: linking_type: [static, dynamic] - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 @@ -113,7 +113,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -226,7 +226,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -277,7 +277,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -349,7 +349,7 @@ jobs: SDK: "Database" strategy: matrix: - os: [macos-13] + os: [macos-14] xcode: [Xcode_15.2] artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] runs-on: ${{ matrix.os }} @@ -403,7 +403,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -462,7 +462,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -509,7 +509,7 @@ jobs: needs: package-head env: FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 - runs-on: macos-13 + runs-on: macos-14 steps: - name: Xcode 15.2 run: sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer @@ -546,7 +546,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -602,7 +602,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 @@ -657,7 +657,7 @@ jobs: matrix: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - - os: macos-13 + - os: macos-14 xcode: Xcode_15.2 - os: macos-15 xcode: Xcode_16.1 From 9adc6ed092eb366f70883751928ede9b8612c05a Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 12 Nov 2024 22:30:23 -0500 Subject: [PATCH 29/98] [Infra] Update multiple workflows to use macOS 15 for Xcode 16 (#14105) --- .github/workflows/crashlytics.yml | 25 ++++++++++++++----------- .github/workflows/dynamiclinks.yml | 2 +- .github/workflows/inappmessaging.yml | 15 +++++++++------ .github/workflows/installations.yml | 27 +++++++++++++-------------- .github/workflows/remoteconfig.yml | 27 +++++++++++++-------------- .github/workflows/sessions.yml | 25 ++++++++++++------------- .github/workflows/storage.yml | 4 ++-- 7 files changed, 64 insertions(+), 61 deletions(-) diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 5638d5d35bc..f24d0f63de5 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -25,20 +25,23 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos --skip-tests] - os: [macos-14] flags: [ '--use-modular-headers --skip-tests', '' ] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - uses: nick-fields/retry@v3 with: timeout_minutes: 120 @@ -85,22 +88,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: @@ -149,7 +152,7 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/dynamiclinks.yml b/.github/workflows/dynamiclinks.yml index 61439d6cc3c..9304532dc90 100644 --- a/.github/workflows/dynamiclinks.yml +++ b/.github/workflows/dynamiclinks.yml @@ -114,7 +114,7 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index c8d70fbeff4..9464fa3a245 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -24,14 +24,17 @@ jobs: strategy: matrix: podspec: [FirebaseInAppMessaging.podspec] - os: [macos-14] - xcode: [Xcode_15.2, Xcode_16] - runs-on: ${{ matrix.os }} + build-env: + - os: macos-14 + xcode: Xcode_15.2 + - os: macos-15 + xcode: Xcode_16.1 + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: FirebaseInAppMessaging @@ -97,7 +100,7 @@ jobs: - os: macos-14 xcode: Xcode_15.4 - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -139,7 +142,7 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index 3a1da8aa802..d0913c2ed19 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -25,15 +25,14 @@ jobs: matrix: # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 target: [ios, tvos, macos --skip-tests, watchos] - os: [macos-14] - include: + build-env: - os: macos-14 - xcode: Xcode_15.3 + xcode: Xcode_15.2 test-specs: unit,integration - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 test-specs: unit - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 @@ -50,12 +49,12 @@ jobs: id: secrets run: echo "::set-output name=val::$([[ -z $plist_secret ]] && echo "0" || echo "1")" - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: | export FIS_INTEGRATION_TESTS_REQUIRED=${{ steps.secrets.outputs.val }} scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseInstallations.podspec \ - --platforms=${{ matrix.target }} --test-specs=${{ matrix.test-specs }} + --platforms=${{ matrix.target }} --test-specs=${{ matrix.build-env.test-specs }} spm-package-resolved: env: @@ -93,22 +92,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index eb5cae871c7..2036d8ab274 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -62,28 +62,27 @@ jobs: # TODO: macos tests are blocked by https://github.com/erikdoe/ocmock/pull/532 target: [ios, tvos, macos --skip-tests, watchos] podspec: [FirebaseRemoteConfig.podspec] - os: [macos-14] - include: + build-env: - os: macos-14 xcode: Xcode_15.3 # TODO(#13078): Fix testing infra to enforce warnings again. tests: --allow-warnings # Flaky tests on CI - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 tests: --skip-tests - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Build and test run: | scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} \ - ${{ matrix.tests }} + ${{ matrix.build-env.tests }} spm-package-resolved: env: @@ -124,27 +123,27 @@ jobs: target: iOS test: spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS test: spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS test: spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS test: spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS test: spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst test: spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS test: spm runs-on: ${{ matrix.os }} @@ -184,7 +183,7 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/sessions.yml b/.github/workflows/sessions.yml index 73fff13c7aa..cddd363aebe 100644 --- a/.github/workflows/sessions.yml +++ b/.github/workflows/sessions.yml @@ -24,30 +24,29 @@ jobs: strategy: matrix: target: [ios, tvos, macos, watchos] - os: [macos-14] - include: + build-env: - os: macos-14 xcode: Xcode_15.3 tests: # Flaky tests on CI - - os: macos-14 - xcode: Xcode_16 + - os: macos-15 + xcode: Xcode_16.1 tests: --skip-tests - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - uses: nick-fields/retry@v3 with: timeout_minutes: 120 max_attempts: 3 retry_on: error retry_wait_seconds: 120 - command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec --platforms=${{ matrix.target }} ${{ matrix.tests }} + command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }} spm-package-resolved: env: @@ -86,22 +85,22 @@ jobs: xcode: Xcode_15.4 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 220f98b5741..790e8ebd39d 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -139,8 +139,8 @@ jobs: #- os: macos-13 # xcode: Xcode_14.2 # TODO: the legacy ObjC quickstart doesn't build with Xcode 15. - swift: swift - os: macos-14 - xcode: Xcode_15.3 + os: macos-15 + xcode: Xcode_16.1 env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} From c94b2c0c1fda1fd93e30549eb40dd96c970e6aec Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 12 Nov 2024 23:18:28 -0500 Subject: [PATCH 30/98] [Release] Update versions for Release 11.6.0 (#14104) --- Firebase.podspec | 48 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAnalytics.podspec | 8 ++-- FirebaseAnalyticsOnDeviceConversion.podspec | 4 +- FirebaseAppCheck.podspec | 4 +- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 4 +- FirebaseAuth.podspec | 6 +-- FirebaseAuthInterop.podspec | 2 +- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 4 +- FirebaseDatabase.podspec | 4 +- FirebaseDynamicLinks.podspec | 4 +- FirebaseFirestore.podspec | 8 ++-- FirebaseFirestoreInternal.podspec | 4 +- FirebaseFunctions.podspec | 6 +-- FirebaseInAppMessaging.podspec | 4 +- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 6 +-- FirebaseMessaging.podspec | 4 +- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 4 +- FirebaseRemoteConfig.podspec | 4 +- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 6 +-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 6 +-- FirebaseVertexAI.podspec | 6 +-- GoogleAppMeasurement.podspec | 4 +- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 34 files changed, 91 insertions(+), 91 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index 50b992a43d1..feb7cf04643 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 11.5.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 11.5.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 11.5.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 11.6.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 11.6.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 11.6.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '11.5.0' + ss.dependency 'FirebaseCore', '11.6.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -79,13 +79,13 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.5.0' + ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.6.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 11.5.0' + ss.dependency 'FirebaseABTesting', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -95,13 +95,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 11.5.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 11.6.0-beta' ss.ios.deployment_target = '13.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 11.5.0' + ss.dependency 'FirebaseAppCheck', '~> 11.6.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -110,7 +110,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 11.5.0' + ss.dependency 'FirebaseAuth', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -120,7 +120,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 11.5.0' + ss.dependency 'FirebaseCrashlytics', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' @@ -130,7 +130,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 11.5.0' + ss.dependency 'FirebaseDatabase', '~> 11.6.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -140,13 +140,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'DynamicLinks' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.5.0' + ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.6.0' ss.ios.deployment_target = '13.0' end s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 11.5.0' + ss.dependency 'FirebaseFirestore', '~> 11.6.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -154,7 +154,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 11.5.0' + ss.dependency 'FirebaseFunctions', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -164,20 +164,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.5.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.5.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.6.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.6.0-beta' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 11.5.0' + ss.dependency 'FirebaseInstallations', '~> 11.6.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 11.5.0' + ss.dependency 'FirebaseMessaging', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -187,7 +187,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 11.5.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 11.6.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -197,15 +197,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 11.5.0' - ss.tvos.dependency 'FirebasePerformance', '~> 11.5.0' + ss.ios.dependency 'FirebasePerformance', '~> 11.6.0' + ss.tvos.dependency 'FirebasePerformance', '~> 11.6.0' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 11.5.0' + ss.dependency 'FirebaseRemoteConfig', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -215,7 +215,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 11.5.0' + ss.dependency 'FirebaseStorage', '~> 11.6.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index d988bbac272..e008e487346 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -52,7 +52,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 125dd7e6f01..8644234365b 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.0' @@ -37,12 +37,12 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement', '11.5.0' + ss.dependency 'GoogleAppMeasurement', '11.6.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.5.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.6.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index e03608aa555..4d57ab96f1b 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalyticsOnDeviceConversion' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'On device conversion measurement plugin for FirebaseAnalytics. Not intended for direct use.' s.description = <<-DESC @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.5.0' + s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.6.0' s.static_framework = true diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index a80ebd8451a..7de86c0d15a 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -46,7 +46,7 @@ Pod::Spec.new do |s| s.dependency 'AppCheckCore', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 0496fe9832b..fe888c5a945 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index c5230bda665..93da174d545 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '11.5.0-beta' + s.version = '11.6.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,7 +30,7 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' s.dependency 'FirebaseInstallations', '~> 11.0' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 67f32a30b74..676946fb764 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -58,8 +58,8 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.framework = 'SafariServices' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index 91dbd50ff5b..872de49ce94 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index c2ccb23fddc..93802226db5 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/Logger', '~> 8.0' - s.dependency 'FirebaseCoreInternal', '11.5' + s.dependency 'FirebaseCoreInternal', '11.6.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 59dfad21719..9e8002873b7 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index 30fc10e914a..6cab3696090 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 5426a42bbee..62d4ab26c54 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,7 +59,7 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 834211167ba..5366356eca1 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -47,7 +47,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index 3d6ce244d8c..a333465a2b2 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDynamicLinks' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Dynamic Links' s.description = <<-DESC @@ -34,7 +34,7 @@ Firebase Dynamic Links are deep links that enhance user experience and increase } s.frameworks = 'QuartzCore' s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index ff55ec358f1..43185b9843c 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' - s.dependency 'FirebaseFirestoreInternal', '11.5.0' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseFirestoreInternal', '11.6.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 33a61dbca85..e4f2c079434 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -93,7 +93,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, } s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' abseil_version = '~> 1.20240116.1' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index fb9d748f4cb..fcf525f91fd 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,8 +35,8 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseMessagingInterop', '~> 11.0' diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 9aa37623b15..8202e16f576 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '11.5.0-beta' + s.version = '11.6.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,7 +80,7 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 377902f1df6..e0c7b144fa3 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 6ca985941e8..ed25e155ae0 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '11.5.0-beta' + s.version = '11.6.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,8 +36,8 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index c826363f9e5..8345334c136 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -62,7 +62,7 @@ device, and it is completely free. s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Reachability', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index 001c05f57c4..b95739b71be 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 1215fa057f4..a6fedbfe4c2 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -59,7 +59,7 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseRemoteConfig', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index d8dfbe3aa84..e670d667856 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -52,7 +52,7 @@ app update. } s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.0' diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 197604250f2..1e8a2078665 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index f36099d413d..7097ae4861e 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,8 +39,8 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index ab2345bb104..287e3bef90c 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index bcbe118149b..26162cb0e07 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -39,8 +39,8 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index a6aa6ea5b56..75e53f517c5 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseVertexAI' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Vertex AI in Firebase SDK' s.description = <<-DESC @@ -46,8 +46,8 @@ Firebase SDK. s.dependency 'FirebaseAppCheckInterop', '~> 11.4' s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '11.5' - s.dependency 'FirebaseCoreExtension', '11.5' + s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCoreExtension', '11.6.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index aa4ec6509b7..25b05e666bc 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.5.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.6.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 8250337d28d..5c9f9f8ca2c 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurementOnDeviceConversion' - s.version = '11.5.0' + s.version = '11.6.0' s.summary = <<-SUMMARY On device conversion measurement plugin for Google App Measurement. Not intended for direct use. diff --git a/Package.swift b/Package.swift index 1fa4deed10a..73151c6c226 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ import class Foundation.ProcessInfo import PackageDescription -let firebaseVersion = "11.5.0" +let firebaseVersion = "11.6.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 17d32d4c985..7c461aaf66a 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "11.5.0", + version: "11.6.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From 4ab30d61d397e7fde1d5a4f0a7abe7621c72fcfd Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Wed, 13 Nov 2024 11:43:58 -0500 Subject: [PATCH 31/98] [Auth] First pass marking closures as Sendable --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 37 +++++++++++-------- .../Swift/AuthProvider/OAuthProvider.swift | 2 +- .../AuthProvider/PhoneAuthProvider.swift | 2 +- FirebaseAuth/Sources/Swift/User/User.swift | 35 +++++++++--------- .../Swift/User/UserProfileChangeRequest.swift | 2 +- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index e5ccdaafac7..171db121e62 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -219,7 +219,8 @@ extension Auth: AuthInterop { /// - user: The user object to be set as the current user of the calling Auth instance. /// - completion: Optionally; a block invoked after the user of the calling Auth instance has /// been updated or an error was encountered. - @objc open func updateCurrentUser(_ user: User?, completion: ((Error?) -> Void)? = nil) { + @objc open func updateCurrentUser(_ user: User?, + completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { guard let user else { let error = AuthErrorUtils.nullUserError(message: nil) @@ -286,7 +287,7 @@ extension Auth: AuthInterop { ) #endif // !FIREBASE_CI @objc open func fetchSignInMethods(forEmail email: String, - completion: (([String]?, Error?) -> Void)? = nil) { + completion: (@Sendable ([String]?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let request = CreateAuthURIRequest(identifier: email, continueURI: "http://www.google.com/", @@ -350,7 +351,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withEmail email: String, password: String, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) Task { @@ -449,7 +450,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withEmail email: String, link: String, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) let credential = EmailAuthCredential(withEmail: email, link: link) @@ -528,7 +529,7 @@ extension Auth: AuthInterop { @objc(signInWithProvider:UIDelegate:completion:) open func signIn(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: ((AuthDataResult?, Error?) -> Void)?) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)?) { kAuthGlobalWorkQueue.async { Task { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) @@ -629,7 +630,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc(signInWithCredential:completion:) open func signIn(with credential: AuthCredential, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) Task { @@ -699,7 +700,8 @@ extension Auth: AuthInterop { /// not enabled. Enable them in the Auth section of the Firebase console. /// - Parameter completion: Optionally; a block which is invoked when the sign in finishes, or is /// canceled. Invoked asynchronously on the main thread in the future. - @objc open func signInAnonymously(completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + @objc open func signInAnonymously(completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = + nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) if let currentUser = self.currentUser, currentUser.isAnonymous { @@ -765,7 +767,7 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the sign in finishes, or is /// canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withCustomToken token: String, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) let request = VerifyCustomTokenRequest(token: token, @@ -834,7 +836,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func createUser(withEmail email: String, password: String, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { guard password.count > 0 else { if let completion { completion(nil, AuthErrorUtils.weakPasswordError(serverResponseReason: "Missing password")) @@ -947,7 +949,7 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. @objc open func confirmPasswordReset(withCode code: String, newPassword: String, - completion: @escaping (Error?) -> Void) { + completion: @Sendable @escaping (Error?) -> Void) { kAuthGlobalWorkQueue.async { let request = ResetPasswordRequest(oobCode: code, newPassword: newPassword, @@ -987,7 +989,8 @@ extension Auth: AuthInterop { /// Invoked /// asynchronously on the main thread in the future. @objc open func checkActionCode(_ code: String, - completion: @escaping (ActionCodeInfo?, Error?) -> Void) { + completion: @Sendable @escaping (ActionCodeInfo?, Error?) + -> Void) { kAuthGlobalWorkQueue.async { let request = ResetPasswordRequest(oobCode: code, newPassword: nil, @@ -1032,7 +1035,8 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. @objc open func verifyPasswordResetCode(_ code: String, - completion: @escaping (String?, Error?) -> Void) { + completion: @Sendable @escaping (String?, Error?) + -> Void) { checkActionCode(code) { info, error in if let error { completion(nil, error) @@ -1065,7 +1069,8 @@ extension Auth: AuthInterop { /// - Parameter code: The out of band code to be applied. /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. - @objc open func applyActionCode(_ code: String, completion: @escaping (Error?) -> Void) { + @objc open func applyActionCode(_ code: String, + completion: @Sendable @escaping (Error?) -> Void) { kAuthGlobalWorkQueue.async { let request = SetAccountInfoRequest(requestConfiguration: self.requestConfiguration) request.oobCode = code @@ -1110,7 +1115,7 @@ extension Auth: AuthInterop { /// Invoked /// asynchronously on the main thread in the future. @objc open func sendPasswordReset(withEmail email: String, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { sendPasswordReset(withEmail: email, actionCodeSettings: nil, completion: completion) } @@ -1143,7 +1148,7 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. @objc open func sendPasswordReset(withEmail email: String, actionCodeSettings: ActionCodeSettings?, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let request = GetOOBConfirmationCodeRequest.passwordResetRequest( email: email, @@ -1212,7 +1217,7 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. @objc open func sendSignInLink(toEmail email: String, actionCodeSettings: ActionCodeSettings, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { if !actionCodeSettings.handleCodeInApp { fatalError("The handleCodeInApp flag in ActionCodeSettings must be true for Email-link " + "Authentication.") diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift index b8cca1f5fca..e74743fa9a5 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift @@ -268,7 +268,7 @@ import Foundation /// - Parameter completion: Optionally; a block which is invoked asynchronously on the main /// thread when the mobile web flow is completed. open func getCredentialWith(_ uiDelegate: AuthUIDelegate?, - completion: ((AuthCredential?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthCredential?, Error?) -> Void)? = nil) { guard let urlTypes = auth.mainBundleUrlTypes, AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, urlTypes: urlTypes) else { diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 2a1de385aa4..8de4229f2ef 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -71,7 +71,7 @@ import Foundation open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession? = nil, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@Sendable (_: String?, _: Error?) -> Void)?) { guard AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, urlTypes: auth.mainBundleUrlTypes) else { fatalError( diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index fccd96ab088..098d21fa83f 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -101,7 +101,7 @@ extension User: NSSecureCoding {} ) #endif // !FIREBASE_CI @objc(updateEmail:completion:) - open func updateEmail(to email: String, completion: ((Error?) -> Void)? = nil) { + open func updateEmail(to email: String, completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.updateEmail(email: email, password: nil) { error in User.callInMainThreadWithError(callback: completion, error: error) @@ -173,7 +173,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the user profile change has /// finished. @objc(updatePassword:completion:) - open func updatePassword(to password: String, completion: ((Error?) -> Void)? = nil) { + open func updatePassword(to password: String, completion: (@Sendable (Error?) -> Void)? = nil) { guard password.count > 0 else { if let completion { completion(AuthErrorUtils.weakPasswordError(serverResponseReason: "Missing Password")) @@ -234,7 +234,7 @@ extension User: NSSecureCoding {} /// finished. @objc(updatePhoneNumberCredential:completion:) open func updatePhoneNumber(_ credential: PhoneAuthCredential, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalUpdateOrLinkPhoneNumber(credential: credential, isLinkOperation: false) { error in @@ -303,7 +303,7 @@ extension User: NSSecureCoding {} /// `updateEmail(to:)`. /// - Parameter completion: Optionally; the block invoked when the reload has finished. Invoked /// asynchronously on the main thread in the future. - @objc open func reload(completion: ((Error?) -> Void)? = nil) { + @objc open func reload(completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.getAccountInfoRefreshingCache { user, error in User.callInMainThreadWithError(callback: completion, error: error) @@ -361,7 +361,7 @@ extension User: NSSecureCoding {} /// finished. Invoked asynchronously on the main thread in the future. @objc(reauthenticateWithCredential:completion:) open func reauthenticate(with credential: AuthCredential, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -463,7 +463,7 @@ extension User: NSSecureCoding {} @objc(reauthenticateWithProvider:UIDelegate:completion:) open func reauthenticate(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -507,7 +507,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the token is available. Invoked /// asynchronously on the main thread in the future. @objc(getIDTokenWithCompletion:) - open func getIDToken(completion: ((String?, Error?) -> Void)?) { + open func getIDToken(completion: (@Sendable (String?, Error?) -> Void)?) { // |getIDTokenForcingRefresh:completion:| is also a public API so there is no need to dispatch to // global work queue here. getIDTokenForcingRefresh(false, completion: completion) @@ -523,7 +523,7 @@ extension User: NSSecureCoding {} /// asynchronously on the main thread in the future. @objc(getIDTokenForcingRefresh:completion:) open func getIDTokenForcingRefresh(_ forceRefresh: Bool, - completion: ((String?, Error?) -> Void)?) { + completion: (@Sendable (String?, Error?) -> Void)?) { getIDTokenResult(forcingRefresh: forceRefresh) { tokenResult, error in if let completion { DispatchQueue.main.async { @@ -563,7 +563,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the token is available. Invoked /// asynchronously on the main thread in the future. @objc(getIDTokenResultWithCompletion:) - open func getIDTokenResult(completion: ((AuthTokenResult?, Error?) -> Void)?) { + open func getIDTokenResult(completion: (@Sendable (AuthTokenResult?, Error?) -> Void)?) { getIDTokenResult(forcingRefresh: false) { tokenResult, error in if let completion { DispatchQueue.main.async { @@ -584,7 +584,7 @@ extension User: NSSecureCoding {} /// asynchronously on the main thread in the future. @objc(getIDTokenResultForcingRefresh:completion:) open func getIDTokenResult(forcingRefresh: Bool, - completion: ((AuthTokenResult?, Error?) -> Void)?) { + completion: (@Sendable (AuthTokenResult?, Error?) -> Void)?) { kAuthGlobalWorkQueue.async { self.internalGetToken(forceRefresh: forcingRefresh, backend: self.backend) { token, error in var tokenResult: AuthTokenResult? @@ -660,7 +660,7 @@ extension User: NSSecureCoding {} /// fails. @objc(linkWithCredential:completion:) open func link(with credential: AuthCredential, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { if self.providerDataRaw[credential.provider] != nil { User.callInMainThreadWithAuthDataResultAndError( @@ -747,7 +747,7 @@ extension User: NSSecureCoding {} @objc(linkWithProvider:UIDelegate:completion:) open func link(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: ((AuthDataResult?, Error?) -> Void)? = nil) { + completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -847,7 +847,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the request to send an email /// verification is complete, or fails. Invoked asynchronously on the main thread in the future. @objc(sendEmailVerificationWithCompletion:) - open func __sendEmailVerification(withCompletion completion: ((Error?) -> Void)?) { + open func __sendEmailVerification(withCompletion completion: (@Sendable (Error?) -> Void)?) { sendEmailVerification(completion: completion) } @@ -867,7 +867,7 @@ extension User: NSSecureCoding {} /// verification is complete, or fails. Invoked asynchronously on the main thread in the future. @objc(sendEmailVerificationWithActionCodeSettings:completion:) open func sendEmailVerification(with actionCodeSettings: ActionCodeSettings? = nil, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { @@ -932,7 +932,7 @@ extension User: NSSecureCoding {} /// `reauthenticate(with:)`. /// - Parameter completion: Optionally; the block invoked when the request to delete the account /// is complete, or fails. Invoked asynchronously on the main thread in the future. - @objc open func delete(completion: ((Error?) -> Void)? = nil) { + @objc open func delete(completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { @@ -985,7 +985,8 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the request to send the /// verification email is complete, or fails. @objc(sendEmailVerificationBeforeUpdatingEmail:completion:) - open func __sendEmailVerificationBeforeUpdating(email: String, completion: ((Error?) -> Void)?) { + open func __sendEmailVerificationBeforeUpdating(email: String, + completion: (@Sendable (Error?) -> Void)?) { sendEmailVerification(beforeUpdatingEmail: email, completion: completion) } @@ -997,7 +998,7 @@ extension User: NSSecureCoding {} /// verification email is complete, or fails. @objc open func sendEmailVerification(beforeUpdatingEmail email: String, actionCodeSettings: ActionCodeSettings? = nil, - completion: ((Error?) -> Void)? = nil) { + completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { diff --git a/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift b/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift index 493f3d80f92..f7a5c67702b 100644 --- a/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift +++ b/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift @@ -59,7 +59,7 @@ import Foundation /// This method should only be called once.Once called, property values should not be changed. /// - Parameter completion: Optionally; the block invoked when the user profile change has been /// applied. - @objc open func commitChanges(completion: ((Error?) -> Void)? = nil) { + @objc open func commitChanges(completion: (@Sendable (Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { if self.consumed { fatalError("Internal Auth Error: commitChanges should only be called once.") From 87925edd799f39edc6664a7f2250409c1653738e Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Wed, 13 Nov 2024 11:44:48 -0500 Subject: [PATCH 32/98] Extra fixes --- .../Sources/Swift/AuthProvider/PhoneAuthProvider.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 8de4229f2ef..92e1a722e20 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -52,7 +52,7 @@ import Foundation @objc(verifyPhoneNumber:UIDelegate:completion:) open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@Sendable (_: String?, _: Error?) -> Void)?) { verifyPhoneNumber(phoneNumber, uiDelegate: uiDelegate, multiFactorSession: nil, @@ -132,7 +132,7 @@ import Foundation open func verifyPhoneNumber(with multiFactorInfo: PhoneMultiFactorInfo, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession?, - completion: ((_: String?, _: Error?) -> Void)?) { + completion: (@Sendable (_: String?, _: Error?) -> Void)?) { multiFactorSession?.multiFactorInfo = multiFactorInfo verifyPhoneNumber(multiFactorInfo.phoneNumber, uiDelegate: uiDelegate, From 709a685a99a942f00db7a9a057e1ba8dd95b4ce3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:55:58 -0500 Subject: [PATCH 33/98] [Auth] Revert unintentional commits on main (#14108) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 37 ++++++++----------- .../Swift/AuthProvider/OAuthProvider.swift | 2 +- .../AuthProvider/PhoneAuthProvider.swift | 6 +-- FirebaseAuth/Sources/Swift/User/User.swift | 35 +++++++++--------- .../Swift/User/UserProfileChangeRequest.swift | 2 +- 5 files changed, 38 insertions(+), 44 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 171db121e62..e5ccdaafac7 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -219,8 +219,7 @@ extension Auth: AuthInterop { /// - user: The user object to be set as the current user of the calling Auth instance. /// - completion: Optionally; a block invoked after the user of the calling Auth instance has /// been updated or an error was encountered. - @objc open func updateCurrentUser(_ user: User?, - completion: (@Sendable (Error?) -> Void)? = nil) { + @objc open func updateCurrentUser(_ user: User?, completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { guard let user else { let error = AuthErrorUtils.nullUserError(message: nil) @@ -287,7 +286,7 @@ extension Auth: AuthInterop { ) #endif // !FIREBASE_CI @objc open func fetchSignInMethods(forEmail email: String, - completion: (@Sendable ([String]?, Error?) -> Void)? = nil) { + completion: (([String]?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let request = CreateAuthURIRequest(identifier: email, continueURI: "http://www.google.com/", @@ -351,7 +350,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withEmail email: String, password: String, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) Task { @@ -450,7 +449,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withEmail email: String, link: String, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) let credential = EmailAuthCredential(withEmail: email, link: link) @@ -529,7 +528,7 @@ extension Auth: AuthInterop { @objc(signInWithProvider:UIDelegate:completion:) open func signIn(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)?) { + completion: ((AuthDataResult?, Error?) -> Void)?) { kAuthGlobalWorkQueue.async { Task { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) @@ -630,7 +629,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc(signInWithCredential:completion:) open func signIn(with credential: AuthCredential, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) Task { @@ -700,8 +699,7 @@ extension Auth: AuthInterop { /// not enabled. Enable them in the Auth section of the Firebase console. /// - Parameter completion: Optionally; a block which is invoked when the sign in finishes, or is /// canceled. Invoked asynchronously on the main thread in the future. - @objc open func signInAnonymously(completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = - nil) { + @objc open func signInAnonymously(completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) if let currentUser = self.currentUser, currentUser.isAnonymous { @@ -767,7 +765,7 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the sign in finishes, or is /// canceled. Invoked asynchronously on the main thread in the future. @objc open func signIn(withCustomToken token: String, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) let request = VerifyCustomTokenRequest(token: token, @@ -836,7 +834,7 @@ extension Auth: AuthInterop { /// or is canceled. Invoked asynchronously on the main thread in the future. @objc open func createUser(withEmail email: String, password: String, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { guard password.count > 0 else { if let completion { completion(nil, AuthErrorUtils.weakPasswordError(serverResponseReason: "Missing password")) @@ -949,7 +947,7 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. @objc open func confirmPasswordReset(withCode code: String, newPassword: String, - completion: @Sendable @escaping (Error?) -> Void) { + completion: @escaping (Error?) -> Void) { kAuthGlobalWorkQueue.async { let request = ResetPasswordRequest(oobCode: code, newPassword: newPassword, @@ -989,8 +987,7 @@ extension Auth: AuthInterop { /// Invoked /// asynchronously on the main thread in the future. @objc open func checkActionCode(_ code: String, - completion: @Sendable @escaping (ActionCodeInfo?, Error?) - -> Void) { + completion: @escaping (ActionCodeInfo?, Error?) -> Void) { kAuthGlobalWorkQueue.async { let request = ResetPasswordRequest(oobCode: code, newPassword: nil, @@ -1035,8 +1032,7 @@ extension Auth: AuthInterop { /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. @objc open func verifyPasswordResetCode(_ code: String, - completion: @Sendable @escaping (String?, Error?) - -> Void) { + completion: @escaping (String?, Error?) -> Void) { checkActionCode(code) { info, error in if let error { completion(nil, error) @@ -1069,8 +1065,7 @@ extension Auth: AuthInterop { /// - Parameter code: The out of band code to be applied. /// - Parameter completion: Optionally; a block which is invoked when the request finishes. /// Invoked asynchronously on the main thread in the future. - @objc open func applyActionCode(_ code: String, - completion: @Sendable @escaping (Error?) -> Void) { + @objc open func applyActionCode(_ code: String, completion: @escaping (Error?) -> Void) { kAuthGlobalWorkQueue.async { let request = SetAccountInfoRequest(requestConfiguration: self.requestConfiguration) request.oobCode = code @@ -1115,7 +1110,7 @@ extension Auth: AuthInterop { /// Invoked /// asynchronously on the main thread in the future. @objc open func sendPasswordReset(withEmail email: String, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { sendPasswordReset(withEmail: email, actionCodeSettings: nil, completion: completion) } @@ -1148,7 +1143,7 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. @objc open func sendPasswordReset(withEmail email: String, actionCodeSettings: ActionCodeSettings?, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let request = GetOOBConfirmationCodeRequest.passwordResetRequest( email: email, @@ -1217,7 +1212,7 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. @objc open func sendSignInLink(toEmail email: String, actionCodeSettings: ActionCodeSettings, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { if !actionCodeSettings.handleCodeInApp { fatalError("The handleCodeInApp flag in ActionCodeSettings must be true for Email-link " + "Authentication.") diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift index e74743fa9a5..b8cca1f5fca 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift @@ -268,7 +268,7 @@ import Foundation /// - Parameter completion: Optionally; a block which is invoked asynchronously on the main /// thread when the mobile web flow is completed. open func getCredentialWith(_ uiDelegate: AuthUIDelegate?, - completion: (@Sendable (AuthCredential?, Error?) -> Void)? = nil) { + completion: ((AuthCredential?, Error?) -> Void)? = nil) { guard let urlTypes = auth.mainBundleUrlTypes, AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, urlTypes: urlTypes) else { diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 92e1a722e20..2a1de385aa4 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -52,7 +52,7 @@ import Foundation @objc(verifyPhoneNumber:UIDelegate:completion:) open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, - completion: (@Sendable (_: String?, _: Error?) -> Void)?) { + completion: ((_: String?, _: Error?) -> Void)?) { verifyPhoneNumber(phoneNumber, uiDelegate: uiDelegate, multiFactorSession: nil, @@ -71,7 +71,7 @@ import Foundation open func verifyPhoneNumber(_ phoneNumber: String, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession? = nil, - completion: (@Sendable (_: String?, _: Error?) -> Void)?) { + completion: ((_: String?, _: Error?) -> Void)?) { guard AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, urlTypes: auth.mainBundleUrlTypes) else { fatalError( @@ -132,7 +132,7 @@ import Foundation open func verifyPhoneNumber(with multiFactorInfo: PhoneMultiFactorInfo, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession?, - completion: (@Sendable (_: String?, _: Error?) -> Void)?) { + completion: ((_: String?, _: Error?) -> Void)?) { multiFactorSession?.multiFactorInfo = multiFactorInfo verifyPhoneNumber(multiFactorInfo.phoneNumber, uiDelegate: uiDelegate, diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index 098d21fa83f..fccd96ab088 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -101,7 +101,7 @@ extension User: NSSecureCoding {} ) #endif // !FIREBASE_CI @objc(updateEmail:completion:) - open func updateEmail(to email: String, completion: (@Sendable (Error?) -> Void)? = nil) { + open func updateEmail(to email: String, completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.updateEmail(email: email, password: nil) { error in User.callInMainThreadWithError(callback: completion, error: error) @@ -173,7 +173,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the user profile change has /// finished. @objc(updatePassword:completion:) - open func updatePassword(to password: String, completion: (@Sendable (Error?) -> Void)? = nil) { + open func updatePassword(to password: String, completion: ((Error?) -> Void)? = nil) { guard password.count > 0 else { if let completion { completion(AuthErrorUtils.weakPasswordError(serverResponseReason: "Missing Password")) @@ -234,7 +234,7 @@ extension User: NSSecureCoding {} /// finished. @objc(updatePhoneNumberCredential:completion:) open func updatePhoneNumber(_ credential: PhoneAuthCredential, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalUpdateOrLinkPhoneNumber(credential: credential, isLinkOperation: false) { error in @@ -303,7 +303,7 @@ extension User: NSSecureCoding {} /// `updateEmail(to:)`. /// - Parameter completion: Optionally; the block invoked when the reload has finished. Invoked /// asynchronously on the main thread in the future. - @objc open func reload(completion: (@Sendable (Error?) -> Void)? = nil) { + @objc open func reload(completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.getAccountInfoRefreshingCache { user, error in User.callInMainThreadWithError(callback: completion, error: error) @@ -361,7 +361,7 @@ extension User: NSSecureCoding {} /// finished. Invoked asynchronously on the main thread in the future. @objc(reauthenticateWithCredential:completion:) open func reauthenticate(with credential: AuthCredential, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -463,7 +463,7 @@ extension User: NSSecureCoding {} @objc(reauthenticateWithProvider:UIDelegate:completion:) open func reauthenticate(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -507,7 +507,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the token is available. Invoked /// asynchronously on the main thread in the future. @objc(getIDTokenWithCompletion:) - open func getIDToken(completion: (@Sendable (String?, Error?) -> Void)?) { + open func getIDToken(completion: ((String?, Error?) -> Void)?) { // |getIDTokenForcingRefresh:completion:| is also a public API so there is no need to dispatch to // global work queue here. getIDTokenForcingRefresh(false, completion: completion) @@ -523,7 +523,7 @@ extension User: NSSecureCoding {} /// asynchronously on the main thread in the future. @objc(getIDTokenForcingRefresh:completion:) open func getIDTokenForcingRefresh(_ forceRefresh: Bool, - completion: (@Sendable (String?, Error?) -> Void)?) { + completion: ((String?, Error?) -> Void)?) { getIDTokenResult(forcingRefresh: forceRefresh) { tokenResult, error in if let completion { DispatchQueue.main.async { @@ -563,7 +563,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the token is available. Invoked /// asynchronously on the main thread in the future. @objc(getIDTokenResultWithCompletion:) - open func getIDTokenResult(completion: (@Sendable (AuthTokenResult?, Error?) -> Void)?) { + open func getIDTokenResult(completion: ((AuthTokenResult?, Error?) -> Void)?) { getIDTokenResult(forcingRefresh: false) { tokenResult, error in if let completion { DispatchQueue.main.async { @@ -584,7 +584,7 @@ extension User: NSSecureCoding {} /// asynchronously on the main thread in the future. @objc(getIDTokenResultForcingRefresh:completion:) open func getIDTokenResult(forcingRefresh: Bool, - completion: (@Sendable (AuthTokenResult?, Error?) -> Void)?) { + completion: ((AuthTokenResult?, Error?) -> Void)?) { kAuthGlobalWorkQueue.async { self.internalGetToken(forceRefresh: forcingRefresh, backend: self.backend) { token, error in var tokenResult: AuthTokenResult? @@ -660,7 +660,7 @@ extension User: NSSecureCoding {} /// fails. @objc(linkWithCredential:completion:) open func link(with credential: AuthCredential, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { if self.providerDataRaw[credential.provider] != nil { User.callInMainThreadWithAuthDataResultAndError( @@ -747,7 +747,7 @@ extension User: NSSecureCoding {} @objc(linkWithProvider:UIDelegate:completion:) open func link(with provider: FederatedAuthProvider, uiDelegate: AuthUIDelegate?, - completion: (@Sendable (AuthDataResult?, Error?) -> Void)? = nil) { + completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { Task { do { @@ -847,7 +847,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the request to send an email /// verification is complete, or fails. Invoked asynchronously on the main thread in the future. @objc(sendEmailVerificationWithCompletion:) - open func __sendEmailVerification(withCompletion completion: (@Sendable (Error?) -> Void)?) { + open func __sendEmailVerification(withCompletion completion: ((Error?) -> Void)?) { sendEmailVerification(completion: completion) } @@ -867,7 +867,7 @@ extension User: NSSecureCoding {} /// verification is complete, or fails. Invoked asynchronously on the main thread in the future. @objc(sendEmailVerificationWithActionCodeSettings:completion:) open func sendEmailVerification(with actionCodeSettings: ActionCodeSettings? = nil, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { @@ -932,7 +932,7 @@ extension User: NSSecureCoding {} /// `reauthenticate(with:)`. /// - Parameter completion: Optionally; the block invoked when the request to delete the account /// is complete, or fails. Invoked asynchronously on the main thread in the future. - @objc open func delete(completion: (@Sendable (Error?) -> Void)? = nil) { + @objc open func delete(completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { @@ -985,8 +985,7 @@ extension User: NSSecureCoding {} /// - Parameter completion: Optionally; the block invoked when the request to send the /// verification email is complete, or fails. @objc(sendEmailVerificationBeforeUpdatingEmail:completion:) - open func __sendEmailVerificationBeforeUpdating(email: String, - completion: (@Sendable (Error?) -> Void)?) { + open func __sendEmailVerificationBeforeUpdating(email: String, completion: ((Error?) -> Void)?) { sendEmailVerification(beforeUpdatingEmail: email, completion: completion) } @@ -998,7 +997,7 @@ extension User: NSSecureCoding {} /// verification email is complete, or fails. @objc open func sendEmailVerification(beforeUpdatingEmail email: String, actionCodeSettings: ActionCodeSettings? = nil, - completion: (@Sendable (Error?) -> Void)? = nil) { + completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { self.internalGetToken(backend: self.backend) { accessToken, error in if let error { diff --git a/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift b/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift index f7a5c67702b..493f3d80f92 100644 --- a/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift +++ b/FirebaseAuth/Sources/Swift/User/UserProfileChangeRequest.swift @@ -59,7 +59,7 @@ import Foundation /// This method should only be called once.Once called, property values should not be changed. /// - Parameter completion: Optionally; the block invoked when the user profile change has been /// applied. - @objc open func commitChanges(completion: (@Sendable (Error?) -> Void)? = nil) { + @objc open func commitChanges(completion: ((Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { if self.consumed { fatalError("Internal Auth Error: commitChanges should only be called once.") From 28c3e88859e1dfdb083c1d231cc508f01be8afe7 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:37:32 -0500 Subject: [PATCH 34/98] [Auth] Synchronize static method of AuthDefaultUIDelegate on main actor (#14112) --- .../Sources/Swift/Utilities/AuthDefaultUIDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthDefaultUIDelegate.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthDefaultUIDelegate.swift index 6e7a5b30a57..aa8d3cbec6b 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthDefaultUIDelegate.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthDefaultUIDelegate.swift @@ -26,10 +26,10 @@ /// /// This class should be used in the case that a UIDelegate was expected and necessary to /// continue a given flow, but none was provided. - class AuthDefaultUIDelegate: NSObject, AuthUIDelegate { + final class AuthDefaultUIDelegate: NSObject, AuthUIDelegate { /// Returns a default AuthUIDelegate object. /// - Returns: The default AuthUIDelegate object. - class func defaultUIDelegate() -> AuthUIDelegate? { + @MainActor static func defaultUIDelegate() -> AuthUIDelegate? { if GULAppEnvironmentUtil.isAppExtension() { // iOS App extensions should not call [UIApplication sharedApplication], even if // UIApplication responds to it. From cf30f5a4c8ce38df1932f67448db90bb4ef22ebc Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 13 Nov 2024 17:42:42 -0500 Subject: [PATCH 35/98] [Core] Update FirebaseCore pod deps to allow patch updates (#14113) --- Firebase.podspec | 2 +- FirebaseABTesting.podspec | 2 +- FirebaseAnalytics.podspec | 2 +- FirebaseAppCheck.podspec | 2 +- FirebaseAppDistribution.podspec | 2 +- FirebaseAuth.podspec | 4 ++-- FirebaseCore.podspec | 2 +- FirebaseCoreExtension.podspec | 2 +- FirebaseCrashlytics.podspec | 2 +- FirebaseDatabase.podspec | 2 +- FirebaseDynamicLinks.podspec | 2 +- FirebaseFirestore.podspec | 4 ++-- FirebaseFirestoreInternal.podspec | 2 +- FirebaseFunctions.podspec | 4 ++-- FirebaseInAppMessaging.podspec | 2 +- FirebaseInstallations.podspec | 2 +- FirebaseMLModelDownloader.podspec | 4 ++-- FirebaseMessaging.podspec | 2 +- FirebasePerformance.podspec | 2 +- FirebaseRemoteConfig.podspec | 2 +- FirebaseSessions.podspec | 4 ++-- FirebaseStorage.podspec | 4 ++-- FirebaseVertexAI.podspec | 4 ++-- 23 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index feb7cf04643..c014f07db07 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -43,7 +43,7 @@ Simplify your app development, grow your user base, and monetize more effectivel end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '11.6.0' + ss.dependency 'FirebaseCore', '~> 11.6.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index e008e487346..76a3c6eacc6 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -52,7 +52,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 8644234365b..9e109930a87 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.0' diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 7de86c0d15a..7f8995ac47c 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -46,7 +46,7 @@ Pod::Spec.new do |s| s.dependency 'AppCheckCore', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 93da174d545..647a88b941c 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -30,7 +30,7 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' s.dependency 'FirebaseInstallations', '~> 11.0' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 676946fb764..bdb9ee26263 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -58,8 +58,8 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.framework = 'SafariServices' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 93802226db5..0587b7c19e2 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/Logger', '~> 8.0' - s.dependency 'FirebaseCoreInternal', '11.6.0' + s.dependency 'FirebaseCoreInternal', '~> 11.6.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 9e8002873b7..cbabe65f98d 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' end diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 62d4ab26c54..fb0d09d97de 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -59,7 +59,7 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 5366356eca1..f6120d4915e 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -47,7 +47,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index a333465a2b2..dda7be4f589 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -34,7 +34,7 @@ Firebase Dynamic Links are deep links that enhance user experience and increase } s.frameworks = 'QuartzCore' s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index 43185b9843c..92f5e3924c8 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -35,8 +35,8 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'FirebaseFirestoreInternal', '11.6.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index e4f2c079434..704b099c0a1 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -93,7 +93,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, } s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' abseil_version = '~> 1.20240116.1' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index fcf525f91fd..e95980c98ee 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -35,8 +35,8 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseMessagingInterop', '~> 11.0' diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 8202e16f576..53fe204fde8 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -80,7 +80,7 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index e0c7b144fa3..3476e780078 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index ed25e155ae0..879282861a3 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -36,8 +36,8 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 8345334c136..95ac97e6631 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -62,7 +62,7 @@ device, and it is completely free. s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Reachability', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index a6fedbfe4c2..c35aa20a3cc 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -59,7 +59,7 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseRemoteConfig', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index e670d667856..03eeb4bf80b 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -52,7 +52,7 @@ app update. } s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.0' diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 7097ae4861e..d54cf449d3c 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -39,8 +39,8 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 26162cb0e07..753a4b558c5 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -39,8 +39,8 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index 75e53f517c5..fdfe4d0a3e1 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -46,8 +46,8 @@ Firebase SDK. s.dependency 'FirebaseAppCheckInterop', '~> 11.4' s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '11.6.0' - s.dependency 'FirebaseCoreExtension', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCoreExtension', '~> 11.6.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' From d3f686c1f8b4e6a1e8f3668e907cd07ffef319fc Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 13 Nov 2024 18:27:01 -0500 Subject: [PATCH 36/98] [Release] Add `FirebaseCombineSwift` to `FirebaseManifest` (#14110) --- FirebaseCombineSwift.podspec | 4 ++-- .../Sources/FirebaseManifest/FirebaseManifest.swift | 2 ++ ReleaseTooling/Sources/FirebaseManifest/Pod.swift | 3 +++ ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index a181b9b1a42..ba5d25bb0d7 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '11.0.0' + s.version = '11.6.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,7 +51,7 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '11.5' + s.dependency 'FirebaseCore', '11.6.0' s.dependency 'FirebaseAuth', '~> 11.0' s.dependency 'FirebaseFunctions', '~> 11.0' s.dependency 'FirebaseFirestore', '~> 11.0' diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 7c461aaf66a..bf28d99c158 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -55,6 +55,7 @@ public let shared = Manifest( Pod("FirebaseMLModelDownloader", isBeta: true, zip: true), Pod("FirebaseVertexAI", zip: true), Pod("Firebase", allowWarnings: true, platforms: ["ios", "tvos", "macos"], zip: true), + Pod("FirebaseCombineSwift", releasing: false, zip: false), ] ) @@ -64,6 +65,7 @@ public struct Manifest { public let pods: [Pod] public func versionString(_ pod: Pod) -> String { + let version = pod.podVersion ?? self.version return pod.isBeta ? version + "-beta" : version } } diff --git a/ReleaseTooling/Sources/FirebaseManifest/Pod.swift b/ReleaseTooling/Sources/FirebaseManifest/Pod.swift index ca11ba35b23..0bb5c19a208 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/Pod.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/Pod.swift @@ -28,6 +28,8 @@ public struct Pod { public let allowWarnings: Bool /// Set of platforms (e.g. "ios", "macos", "tvos", or "watchos") to build this pod for. public let platforms: Set + /// Allows overriding the ``Manifest/version`` for this pod; defaults to `nil`. + public let podVersion: String? /// Whether or not the pod is planned for publicly releasing (as some pods are for /// internal/testing use). public let releasing: Bool @@ -47,6 +49,7 @@ public struct Pod { self.isBeta = isBeta self.allowWarnings = allowWarnings self.platforms = platforms + self.podVersion = podVersion self.releasing = releasing self.zip = zip } diff --git a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift index 992ed2e9d89..d19cd4c32e5 100644 --- a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift @@ -361,7 +361,7 @@ struct ZipBuilder { /// - Throws: One of many errors that could have happened during the build phase. func buildAndAssembleFirebaseRelease(templateDir: URL) throws -> ReleaseArtifacts { let manifest = FirebaseManifest.shared - var podsToInstall = manifest.pods.map { + var podsToInstall = manifest.pods.filter { $0.releasing }.map { CocoaPodUtils.VersionedPod(name: $0.name, version: manifest.versionString($0), platforms: $0.platforms) From 07aeb8b7704eedfc33c3fb1430b1bb53a99a5102 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 13 Nov 2024 18:29:30 -0500 Subject: [PATCH 37/98] [Combine] Update FirebaseCore pod dep to allow patch updates (#14115) --- FirebaseCombineSwift.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index ba5d25bb0d7..877521ac9a4 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -51,7 +51,7 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.6.0' s.dependency 'FirebaseAuth', '~> 11.0' s.dependency 'FirebaseFunctions', '~> 11.0' s.dependency 'FirebaseFirestore', '~> 11.0' From 33f84199c58bf4a88ea3d388d46b067d1df9195e Mon Sep 17 00:00:00 2001 From: Eldhose M Babu Date: Thu, 14 Nov 2024 07:14:08 -0800 Subject: [PATCH 38/98] Updating Advanced test app with live activity support (#14099) --- .../AdvancedSample.xcodeproj/project.pbxproj | 426 +++++++++++++++++- .../AdvancedSample/AdvancedSample/Info.plist | 2 + FirebaseMessaging/Apps/AdvancedSample/Podfile | 2 +- .../SampleLiveActivity/AppIntent.swift | 25 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + .../SampleLiveActivity/Info.plist | 11 + .../SampleLiveActivity.swift | 101 +++++ .../SampleLiveActivityBundle.swift | 24 + .../SampleLiveActivityLiveActivity.swift | 108 +++++ .../SampleLiveActivityView.swift | 42 ++ FirebaseMessaging/Apps/README.md | 2 +- .../Apps/Shared/ContentView.swift | 6 + .../Apps/Shared/LiveActivityView.swift | 153 +++++++ .../SwiftUISample.xcodeproj/project.pbxproj | 62 +++ 17 files changed, 997 insertions(+), 8 deletions(-) create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift create mode 100644 FirebaseMessaging/Apps/Shared/LiveActivityView.swift diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj index 6e3f4f37392..3487b7fbbd5 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj @@ -3,10 +3,27 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ + 2DAD06BA071A722236250BE2 /* Pods_NotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */; }; + 400CC08C2C48300C00CF1777 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 400CC08B2C48300C00CF1777 /* WidgetKit.framework */; }; + 400CC08E2C48300C00CF1777 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 400CC08D2C48300C00CF1777 /* SwiftUI.framework */; }; + 400CC0912C48300C00CF1777 /* SampleLiveActivityBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */; }; + 400CC0932C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 400CC0952C48300C00CF1777 /* SampleLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */; }; + 400CC0972C48300C00CF1777 /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0962C48300C00CF1777 /* AppIntent.swift */; }; + 400CC0992C48300D00CF1777 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 400CC0982C48300D00CF1777 /* Assets.xcassets */; }; + 400CC09D2C48300D00CF1777 /* SampleLiveActivityExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 400CC0A22C4830F400CF1777 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */; }; + 400CC0A62C48347700CF1777 /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; + 400CC0A72C4834E000CF1777 /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; + 400CC0A82C4835DB00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 406330BA2C48397A00F8C9BC /* LiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406330B92C48397A00F8C9BC /* LiveActivityView.swift */; }; + 406330BB2C4839F200F8C9BC /* LiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406330B92C48397A00F8C9BC /* LiveActivityView.swift */; }; + 406330BC2C483A1F00F8C9BC /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 406330BD2C483A2600F8C9BC /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; 519448F4258AEF6F00297021 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519448F3258AEF6F00297021 /* NotificationService.swift */; }; 519448F8258AEF6F00297021 /* NotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 519448F1258AEF6F00297021 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5194490E258AF0B200297021 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5194490D258AF0B200297021 /* Assets.xcassets */; }; @@ -41,9 +58,19 @@ 51C21D212667FBCE0079AEEE /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 51C21D202667FBCE0079AEEE /* GoogleService-Info.plist */; }; 51C24C622589603800236F25 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C24C602589603800236F25 /* LaunchScreen.storyboard */; }; 51C24C652589606B00236F25 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 51C24C642589606B00236F25 /* logo.png */; }; + 7E49101BD3AE69BDA5BD6694 /* Pods_AppClips.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */; }; + 900887ABCA7B64EE026E0B4C /* Pods_AdvancedSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */; }; + D43F963F2DB04638A9D07823 /* Pods_SampleWatchWatchKitExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 400CC09B2C48300D00CF1777 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 51A1F39025883DCE0025932B /* Project object */; + proxyType = 1; + remoteGlobalIDString = 400CC0892C48300C00CF1777; + remoteInfo = SampleLiveActivityExtension; + }; 519448F6258AEF6F00297021 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 51A1F39025883DCE0025932B /* Project object */; @@ -82,6 +109,7 @@ dstSubfolderSpec = 13; files = ( 519448F8258AEF6F00297021 /* NotificationServiceExtension.appex in Embed App Extensions */, + 400CC09D2C48300D00CF1777 /* SampleLiveActivityExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -122,6 +150,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppClips.release.xcconfig"; path = "Target Support Files/Pods-AppClips/Pods-AppClips.release.xcconfig"; sourceTree = ""; }; + 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.xcconfig"; sourceTree = ""; }; + 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleWatchWatchKitExtension.debug.xcconfig"; path = "Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension.debug.xcconfig"; sourceTree = ""; }; + 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppClips.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SampleLiveActivityExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 400CC08B2C48300C00CF1777 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 400CC08D2C48300C00CF1777 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityBundle.swift; sourceTree = ""; }; + 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityLiveActivity.swift; sourceTree = ""; }; + 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivity.swift; sourceTree = ""; }; + 400CC0962C48300C00CF1777 /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = ""; }; + 400CC0982C48300D00CF1777 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 400CC09A2C48300D00CF1777 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityView.swift; sourceTree = ""; }; + 406330B92C48397A00F8C9BC /* LiveActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveActivityView.swift; path = ../../Shared/LiveActivityView.swift; sourceTree = ""; }; + 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AdvancedSample.release.xcconfig"; path = "Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample.release.xcconfig"; sourceTree = ""; }; 519448DE2589900400297021 /* AdvancedSample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AdvancedSample.entitlements; sourceTree = ""; }; 519448F1258AEF6F00297021 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 519448F3258AEF6F00297021 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; @@ -160,13 +205,30 @@ 51C21D202667FBCE0079AEEE /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../Shared/GoogleService-Info.plist"; sourceTree = ""; }; 51C24C612589603800236F25 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = ../../Shared/Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51C24C642589606B00236F25 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = ../../Shared/logo.png; sourceTree = ""; }; + 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AdvancedSample.debug.xcconfig"; path = "Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample.debug.xcconfig"; sourceTree = ""; }; + 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SampleWatchWatchKitExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppClips.debug.xcconfig"; path = "Target Support Files/Pods-AppClips/Pods-AppClips.debug.xcconfig"; sourceTree = ""; }; + B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.xcconfig"; sourceTree = ""; }; + E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleWatchWatchKitExtension.release.xcconfig"; path = "Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension.release.xcconfig"; sourceTree = ""; }; + FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AdvancedSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 400CC0872C48300C00CF1777 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC08E2C48300C00CF1777 /* SwiftUI.framework in Frameworks */, + 400CC08C2C48300C00CF1777 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448EE258AEF6F00297021 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2DAD06BA071A722236250BE2 /* Pods_NotificationServiceExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -174,6 +236,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7E49101BD3AE69BDA5BD6694 /* Pods_AppClips.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -181,6 +244,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D43F963F2DB04638A9D07823 /* Pods_SampleWatchWatchKitExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -188,6 +252,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 900887ABCA7B64EE026E0B4C /* Pods_AdvancedSample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -208,6 +273,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 400CC08F2C48300C00CF1777 /* SampleLiveActivity */ = { + isa = PBXGroup; + children = ( + 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */, + 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */, + 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */, + 400CC0962C48300C00CF1777 /* AppIntent.swift */, + 400CC0982C48300D00CF1777 /* Assets.xcassets */, + 400CC09A2C48300D00CF1777 /* Info.plist */, + 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */, + ); + path = SampleLiveActivity; + sourceTree = ""; + }; 519448F2258AEF6F00297021 /* NotificationServiceExtension */ = { isa = PBXGroup; children = ( @@ -221,6 +300,7 @@ isa = PBXGroup; children = ( 51944B27258B091A00297021 /* GoogleService-Info.plist */, + 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */, 5194490D258AF0B200297021 /* Assets.xcassets */, 51944912258AF0B200297021 /* LaunchScreen.storyboard */, 51944915258AF0B200297021 /* Info.plist */, @@ -279,8 +359,10 @@ 51944906258AF0B100297021 /* AppClips */, 51944952258AF2CF00297021 /* SampleWatchWatchKitApp */, 51944961258AF2D000297021 /* SampleWatchWatchKitExtension */, + 400CC08F2C48300C00CF1777 /* SampleLiveActivity */, 51A1F39925883DCE0025932B /* Products */, 864AA12EFC2050F8D9683C4F /* Pods */, + A47E2AF9ACFCAF48FDA4541E /* Frameworks */, ); sourceTree = ""; }; @@ -293,6 +375,7 @@ 5194494B258AF2CF00297021 /* SampleWatch.app */, 5194494E258AF2CF00297021 /* SampleWatchWatchKitApp.app */, 5194495D258AF2D000297021 /* SampleWatchWatchKitExtension.appex */, + 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */, ); name = Products; sourceTree = ""; @@ -313,6 +396,7 @@ 51A1F3A925883DCF0025932B /* Info.plist */, 51944B9C258B136000297021 /* Assets.xcassets */, 51A1F3A325883DCF0025932B /* Preview Content */, + 406330B92C48397A00F8C9BC /* LiveActivityView.swift */, ); path = AdvancedSample; sourceTree = ""; @@ -328,20 +412,60 @@ 864AA12EFC2050F8D9683C4F /* Pods */ = { isa = PBXGroup; children = ( + 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */, + 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */, + AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */, + 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */, + 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */, + B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */, + 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */, + E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */, ); path = Pods; sourceTree = ""; }; + A47E2AF9ACFCAF48FDA4541E /* Frameworks */ = { + isa = PBXGroup; + children = ( + FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */, + 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */, + 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */, + 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */, + 400CC08B2C48300C00CF1777 /* WidgetKit.framework */, + 400CC08D2C48300C00CF1777 /* SwiftUI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 400CC09E2C48300D00CF1777 /* Build configuration list for PBXNativeTarget "SampleLiveActivityExtension" */; + buildPhases = ( + 400CC0862C48300C00CF1777 /* Sources */, + 400CC0872C48300C00CF1777 /* Frameworks */, + 400CC0882C48300C00CF1777 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SampleLiveActivityExtension; + productName = SampleLiveActivityExtension; + productReference = 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 519448F0258AEF6F00297021 /* NotificationServiceExtension */ = { isa = PBXNativeTarget; buildConfigurationList = 519448FC258AEF6F00297021 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */; buildPhases = ( + 8C560F09F5DF1FB1E11C350A /* [CP] Check Pods Manifest.lock */, 519448ED258AEF6F00297021 /* Sources */, 519448EE258AEF6F00297021 /* Frameworks */, 519448EF258AEF6F00297021 /* Resources */, + C3375D38323C9A9C2D0748C2 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -356,9 +480,11 @@ isa = PBXNativeTarget; buildConfigurationList = 5194491A258AF0B200297021 /* Build configuration list for PBXNativeTarget "AppClips" */; buildPhases = ( + 876710BB6E9D2E92C107B36D /* [CP] Check Pods Manifest.lock */, 51944901258AF0B100297021 /* Sources */, 51944902258AF0B100297021 /* Frameworks */, 51944903258AF0B100297021 /* Resources */, + CA9B73000A77BFF7704A11DF /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -409,9 +535,11 @@ isa = PBXNativeTarget; buildConfigurationList = 51944978258AF2D000297021 /* Build configuration list for PBXNativeTarget "SampleWatchWatchKitExtension" */; buildPhases = ( + 92C865B7E5D6E882C28136ED /* [CP] Check Pods Manifest.lock */, 51944959258AF2D000297021 /* Sources */, 5194495A258AF2D000297021 /* Frameworks */, 5194495B258AF2D000297021 /* Resources */, + BEB20BDE02E635E8C44CCFA5 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -426,17 +554,20 @@ isa = PBXNativeTarget; buildConfigurationList = 51A1F3AC25883DCF0025932B /* Build configuration list for PBXNativeTarget "AdvancedSample" */; buildPhases = ( + A97065E4891968053C6EC4C3 /* [CP] Check Pods Manifest.lock */, 51A1F39425883DCE0025932B /* Sources */, 51A1F39525883DCE0025932B /* Frameworks */, 51A1F39625883DCE0025932B /* Resources */, 519448F9258AEF6F00297021 /* Embed App Extensions */, 5194491D258AF0B200297021 /* Embed App Clips */, + A76C37BD4CD3617B5F47C659 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( 519448F7258AEF6F00297021 /* PBXTargetDependency */, 51944918258AF0B200297021 /* PBXTargetDependency */, + 400CC09C2C48300D00CF1777 /* PBXTargetDependency */, ); name = AdvancedSample; productName = AdvancedSample; @@ -449,9 +580,12 @@ 51A1F39025883DCE0025932B /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1230; + LastSwiftUpdateCheck = 1540; LastUpgradeCheck = 1220; TargetAttributes = { + 400CC0892C48300C00CF1777 = { + CreatedOnToolsVersion = 15.4; + }; 519448F0258AEF6F00297021 = { CreatedOnToolsVersion = 12.3; }; @@ -491,11 +625,20 @@ 5194494A258AF2CF00297021 /* SampleWatch */, 5194494D258AF2CF00297021 /* SampleWatchWatchKitApp */, 5194495C258AF2D000297021 /* SampleWatchWatchKitExtension */, + 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 400CC0882C48300C00CF1777 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC0992C48300D00CF1777 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448EF258AEF6F00297021 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -509,6 +652,7 @@ files = ( 51944914258AF0B200297021 /* LaunchScreen.storyboard in Resources */, 51944B28258B091A00297021 /* GoogleService-Info.plist in Resources */, + 400CC0A22C4830F400CF1777 /* GoogleService-Info.plist in Resources */, 51944911258AF0B200297021 /* Preview Assets.xcassets in Resources */, 5194490E258AF0B200297021 /* Assets.xcassets in Resources */, ); @@ -553,7 +697,178 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 876710BB6E9D2E92C107B36D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-AppClips-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8C560F09F5DF1FB1E11C350A /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-NotificationServiceExtension-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 92C865B7E5D6E882C28136ED /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SampleWatchWatchKitExtension-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + A76C37BD4CD3617B5F47C659 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + A97065E4891968053C6EC4C3 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-AdvancedSample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + BEB20BDE02E635E8C44CCFA5 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + C3375D38323C9A9C2D0748C2 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + CA9B73000A77BFF7704A11DF /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + 400CC0862C48300C00CF1777 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC0A72C4834E000CF1777 /* SampleLiveActivityView.swift in Sources */, + 400CC0912C48300C00CF1777 /* SampleLiveActivityBundle.swift in Sources */, + 400CC0972C48300C00CF1777 /* AppIntent.swift in Sources */, + 400CC0952C48300C00CF1777 /* SampleLiveActivity.swift in Sources */, + 400CC0932C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448ED258AEF6F00297021 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -566,12 +881,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 406330BD2C483A2600F8C9BC /* SampleLiveActivityView.swift in Sources */, 51944924258AF0F500297021 /* AppDelegate.swift in Sources */, 51944930258AF10200297021 /* UserSettings.swift in Sources */, 51944932258AF10200297021 /* TopicView.swift in Sources */, + 406330BC2C483A1F00F8C9BC /* SampleLiveActivityLiveActivity.swift in Sources */, 51944931258AF10200297021 /* Identity.swift in Sources */, 51944928258AF0F900297021 /* SceneDelegate.swift in Sources */, 5194492C258AF0FD00297021 /* ContentView.swift in Sources */, + 406330BB2C4839F200F8C9BC /* LiveActivityView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -591,17 +909,25 @@ buildActionMask = 2147483647; files = ( 51A1F3B125883E370025932B /* AppDelegate.swift in Sources */, + 400CC0A62C48347700CF1777 /* SampleLiveActivityView.swift in Sources */, 51A1F3B525883E630025932B /* SceneDelegate.swift in Sources */, + 406330BA2C48397A00F8C9BC /* LiveActivityView.swift in Sources */, 51A1F3CB25883EFF0025932B /* TopicView.swift in Sources */, 51A1F3B825883E810025932B /* ContentView.swift in Sources */, 51A1F3CA25883EFF0025932B /* UserSettings.swift in Sources */, 51A1F3C625883EF60025932B /* Identity.swift in Sources */, + 400CC0A82C4835DB00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 400CC09C2C48300D00CF1777 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */; + targetProxy = 400CC09B2C48300D00CF1777 /* PBXContainerItemProxy */; + }; 519448F7258AEF6F00297021 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 519448F0258AEF6F00297021 /* NotificationServiceExtension */; @@ -652,8 +978,78 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 400CC09F2C48300D00CF1777 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SampleLiveActivity/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SampleLiveActivity; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev.SampleLiveActivity; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 400CC0A02C48300D00CF1777 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SampleLiveActivity/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SampleLiveActivity; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev.SampleLiveActivity; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 519448FA258AEF6F00297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -676,6 +1072,7 @@ }; 519448FB258AEF6F00297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -698,6 +1095,7 @@ }; 5194491B258AF0B200297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -708,7 +1106,7 @@ DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = AppClips/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -723,6 +1121,7 @@ }; 5194491C258AF0B200297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -733,7 +1132,7 @@ DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = AppClips/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -822,6 +1221,7 @@ }; 51944976258AF2D000297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CODE_SIGN_ENTITLEMENTS = SampleWatchWatchKitExtension/SampleWatchWatchKitExtension.entitlements; @@ -849,6 +1249,7 @@ }; 51944977258AF2D000297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CODE_SIGN_ENTITLEMENTS = SampleWatchWatchKitExtension/SampleWatchWatchKitExtension.entitlements; @@ -925,7 +1326,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -980,7 +1381,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -992,6 +1393,7 @@ }; 51A1F3AD25883DCF0025932B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1007,6 +1409,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D LIVE_ACTIVITY_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Firebase iOS App Extensions Dev"; @@ -1017,6 +1420,7 @@ }; 51A1F3AE25883DCF0025932B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1032,6 +1436,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D LIVE_ACTIVITY_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Firebase iOS App Extensions Dev"; @@ -1043,6 +1448,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 400CC09E2C48300D00CF1777 /* Build configuration list for PBXNativeTarget "SampleLiveActivityExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 400CC09F2C48300D00CF1777 /* Debug */, + 400CC0A02C48300D00CF1777 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 519448FC258AEF6F00297021 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist index 2688b32b32f..6901699a310 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist @@ -20,6 +20,8 @@ 1 LSRequiresIPhoneOS + NSSupportsLiveActivities + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/FirebaseMessaging/Apps/AdvancedSample/Podfile b/FirebaseMessaging/Apps/AdvancedSample/Podfile index b5d8b6cb485..e58554029ee 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/Podfile +++ b/FirebaseMessaging/Apps/AdvancedSample/Podfile @@ -29,7 +29,7 @@ target 'AppClips' do end target 'SampleWatchWatchKitExtension' do - platform :watchos, '6.0' + platform :watchos, '7.0' shared_pods end diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift new file mode 100644 index 00000000000..ba9a861efe3 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 AppIntents +import WidgetKit + +struct ConfigurationAppIntent: WidgetConfigurationIntent { + static var title: LocalizedStringResource = "Configuration" + static var description = IntentDescription("This is an example widget.") + + // An example configurable parameter. + @Parameter(title: "Favorite Emoji", default: "😃") + var favoriteEmoji: String +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..13613e3ee1a --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist new file mode 100644 index 00000000000..0f118fb75e4 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift new file mode 100644 index 00000000000..424dac7c8ac --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift @@ -0,0 +1,101 @@ +// Copyright 2020 Google LLC +// +// 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 SwiftUI +import WidgetKit + +struct Provider: AppIntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) + } + + func snapshot(for configuration: ConfigurationAppIntent, + in context: Context) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } + + func timeline(for configuration: ConfigurationAppIntent, + in context: Context) async -> Timeline { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date( + byAdding: .hour, + value: hourOffset, + to: currentDate + )! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + return Timeline(entries: entries, policy: .atEnd) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationAppIntent +} + +struct SampleLiveActivityEntryView: View { + var entry: Provider.Entry + + var body: some View { + VStack { + Text("Time:") + Text(entry.date, style: .time) + + Text("Favorite Emoji:") + Text(entry.configuration.favoriteEmoji) + } + } +} + +struct SampleLiveActivity: Widget { + let kind: String = "SampleLiveActivity" + + var body: some WidgetConfiguration { + AppIntentConfiguration( + kind: kind, + intent: ConfigurationAppIntent.self, + provider: Provider() + ) { entry in + SampleLiveActivityEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } + } +} + +private extension ConfigurationAppIntent { + static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } +} + +#Preview(as: .systemSmall) { + SampleLiveActivity() +} timeline: { + SimpleEntry(date: .now, configuration: .smiley) + SimpleEntry(date: .now, configuration: .starEyes) +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift new file mode 100644 index 00000000000..06cd5847cee --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// 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 SwiftUI +import WidgetKit + +@main +struct SampleLiveActivityBundle: WidgetBundle { + var body: some Widget { + SampleLiveActivity() + SampleLiveActivityLiveActivity() + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift new file mode 100644 index 00000000000..6c84ad58f7e --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift @@ -0,0 +1,108 @@ +// Copyright 2020 Google LLC +// +// 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 ActivityKit +import SwiftUI +import WidgetKit + +struct SampleLiveActivityAttributes: ActivityAttributes { + public struct ContentState: Codable, Hashable { + enum LVStatus: Float, Codable, Hashable { + case started = 0 + case inProgress = 1 + case completed = 2 + + var description: String { + switch self { + case .started: + return "Your Live Activity is started!" + case .inProgress: + return "Your Live Activity is in progress!" + case .completed: + return "Your Live activity is completed!" + } + } + } + + let status: LVStatus + } + + // Fixed non-changing properties about your activity go here! + var lvInstanceNumber: Double +} + +struct SampleLiveActivityLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: SampleLiveActivityAttributes.self) { context in + // Lock screen/banner UI goes here + VStack { + SampleLiveActivityView(context: context) + } + .activityBackgroundTint(Color.cyan) + .activitySystemActionForegroundColor(Color.black) + + } dynamicIsland: { context in + DynamicIsland { + // Expanded UI goes here. Compose the expanded UI through + // various regions, like leading/trailing/center/bottom + DynamicIslandExpandedRegion(.leading) { + Text("Leading") + } + DynamicIslandExpandedRegion(.trailing) { + Text("Trailing") + } + DynamicIslandExpandedRegion(.bottom) { + Text("Bottom") + // more content + } + } compactLeading: { + Text("L") + } compactTrailing: { + Text("T") + } minimal: { + Text("M") + } + .widgetURL(URL(string: "http://www.apple.com")) + .keylineTint(Color.red) + } + } +} + +private extension SampleLiveActivityAttributes { + static var preview: SampleLiveActivityAttributes { + SampleLiveActivityAttributes(lvInstanceNumber: 1) + } +} + +private extension SampleLiveActivityAttributes.ContentState { + static var stateStarted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.started) + } + + static var stateInProgress: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.inProgress) + } + + static var stateCompleted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.completed) + } +} + +#Preview("Notification", as: .content, using: SampleLiveActivityAttributes.preview) { + SampleLiveActivityLiveActivity() +} contentStates: { + SampleLiveActivityAttributes.ContentState.stateStarted + SampleLiveActivityAttributes.ContentState.stateInProgress + SampleLiveActivityAttributes.ContentState.stateCompleted +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift new file mode 100644 index 00000000000..dc2728b9f3d --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift @@ -0,0 +1,42 @@ +// Copyright 2020 Google LLC +// +// 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 SwiftUI +import WidgetKit + +struct SampleLiveActivityView: View { + let context: ActivityViewContext + + var body: some View { + VStack { + HStack { + Image(systemName: "cup.and.saucer") + ProgressView(value: context.state.status.rawValue, total: 2) + .tint(.black) + .background(Color.brown) + Image(systemName: "cup.and.saucer.fill") + } + .padding(16) + + Text("\(context.state.status.description)") + .font(.system(size: 18, weight: .semibold)) + .padding(.bottom) + Text("Instance No: " + String(context.attributes.lvInstanceNumber)) + .font(.system(size: 18, weight: .semibold)) + .padding(.bottom) + Spacer() + } + .background(Color.brown.opacity(0.6)) + } +} diff --git a/FirebaseMessaging/Apps/README.md b/FirebaseMessaging/Apps/README.md index fc2591f76cb..f80410f3200 100644 --- a/FirebaseMessaging/Apps/README.md +++ b/FirebaseMessaging/Apps/README.md @@ -7,7 +7,7 @@ the sample code. The one inside the AdvancedSample folder is a test app based on the test app in the Sample folder. Both Apps share most of the code in the main target. The AdvancedSample app provides advanced app extensions features, such as Notification Service Extension, Shared -Extension, App Clips and a watchOS app. The advanced sample app has more +Extension, App Clips, Live Activites and a watchOS app. The advanced sample app has more targets than the Sample app and requires your own provisioning profiles and certificates for each extension target to be setup so that it can be run on a real device. diff --git a/FirebaseMessaging/Apps/Shared/ContentView.swift b/FirebaseMessaging/Apps/Shared/ContentView.swift index 6d9cb526f38..37e9cb867f3 100644 --- a/FirebaseMessaging/Apps/Shared/ContentView.swift +++ b/FirebaseMessaging/Apps/Shared/ContentView.swift @@ -58,6 +58,12 @@ struct ContentView: View { Text("Topic") .fontWeight(.semibold) } + #if LIVE_ACTIVITY_ENABLED + NavigationLink(destination: LiveActivityView()) { + Text("Live Activity") + .fontWeight(.semibold) + } + #endif // MARK: Action buttons diff --git a/FirebaseMessaging/Apps/Shared/LiveActivityView.swift b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift new file mode 100644 index 00000000000..e91bd4fd08f --- /dev/null +++ b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift @@ -0,0 +1,153 @@ +// Copyright 2020 Google LLC +// +// 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 ActivityKit +import FirebaseMessaging +import SampleLiveActivityExtension +import SwiftUI + +struct LiveActivityView: View { + @State var activityTokenDict = [String: String]() + + var body: some View { + VStack { + Button("Refresh List") { + Task { + refreshAcitivtyList() + } + }.padding(10) + + Button("Cancel all running Activities") { + cancelAllRunningActivities() + }.padding(10) + + Button("Start Live Activity with push") { + startLiveActivity(supportPush: true) + }.padding(10) + + Button("Start Live Activity without push") { + startLiveActivity(supportPush: false) + }.padding(10) + + List { + ForEach(activityTokenDict.keys.sorted(), id: \.self) { key in + VStack { + Text("ActivityId: " + key).frame(maxWidth: .infinity, alignment: .leading) + + Button("Copy") { + UIPasteboard.general.string = activityTokenDict[key]! + }.frame(alignment: .trailing) + + Text("Push Token: " + activityTokenDict[key]!) + .frame(maxWidth: .infinity, alignment: .leading) + }.padding(10) + } + } + }.onAppear { + refreshAcitivtyList() + } + } + + private func refreshAcitivtyList() { + Task { + activityTokenDict.removeAll() + + let ptsToken = Activity.pushToStartToken + + if ptsToken != nil { + let ptsTokenString = getFormatedToken(token: ptsToken!) + activityTokenDict["PTS"] = ptsTokenString + } else { + activityTokenDict["PTS"] = "Not available yet.!" + Task { + for await ptsToken in Activity + .pushToStartTokenUpdates { + let ptsTokenString = getFormatedToken(token: ptsToken) + activityTokenDict["PTS"] = ptsTokenString + refreshAcitivtyList() + } + } + } + + let activities = Activity.activities + for activity in activities { + if activity.pushToken != nil { + let activityToken = getFormatedToken(token: activity.pushToken!) + activityTokenDict[activity.id] = activityToken + } else { + activityTokenDict[activity.id] = "Not available yet!" + } + } + } + } + + func getFormatedToken(token: Data) -> String { + return token.reduce("") { + $0 + String(format: "%02x", $1) + } + } + + private func startLiveActivity(supportPush: Bool) { + let lAttributes = SampleLiveActivityAttributes(lvInstanceNumber: Date() + .timeIntervalSince1970) + let initialState = SampleLiveActivityAttributes.ContentState(status: .started) + let content = ActivityContent(state: initialState, staleDate: nil, relevanceScore: 1.0) + + if supportPush { + let activity = try? Activity.request( + attributes: lAttributes, + content: content, + pushType: .token + ) + + if activity != nil { + Task { + for await pushToken in activity!.pushTokenUpdates { + let activityToken = getFormatedToken(token: pushToken) + activityTokenDict[activity!.id] = activityToken + refreshAcitivtyList() + } + } + } + } else { + let activity = try? Activity.request( + attributes: lAttributes, + content: content, + pushType: .none + ) + } + + refreshAcitivtyList() + } + + func cancelAllRunningActivities() { + Task { + for activity in Activity.activities { + let initialContentState = SampleLiveActivityAttributes + .ContentState(status: .started) + + await activity.end( + ActivityContent(state: initialContentState, staleDate: Date()), + dismissalPolicy: .immediate + ) + } + + refreshAcitivtyList() + } + } +} + +#Preview { + LiveActivityView() +} diff --git a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj index dd736c2b203..4224b6e136b 100644 --- a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj @@ -15,9 +15,12 @@ 5134F860277EAEC600AEE915 /* SwiftUISampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5134F85F277EAEC600AEE915 /* SwiftUISampleApp.swift */; }; 5134F867277EAEC900AEE915 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5134F866277EAEC900AEE915 /* Preview Assets.xcassets */; }; 5134F86E277EAEF800AEE915 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5134F86D277EAEF800AEE915 /* GoogleService-Info.plist */; }; + CD7B98AE712C5BD92A57F49B /* Pods_SwiftUISample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUISample.debug.xcconfig"; path = "Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample.debug.xcconfig"; sourceTree = ""; }; + 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftUISample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5104EF052787BC590026A7C4 /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Identity.swift; path = ../../Shared/Identity.swift; sourceTree = ""; }; 5104EF062787BC590026A7C4 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContentView.swift; path = ../../Shared/ContentView.swift; sourceTree = ""; }; 5104EF072787BC590026A7C4 /* UserSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserSettings.swift; path = ../../Shared/UserSettings.swift; sourceTree = ""; }; @@ -29,6 +32,7 @@ 5134F86D277EAEF800AEE915 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../Shared/GoogleService-Info.plist"; sourceTree = ""; }; 5134F86F277EAF0A00AEE915 /* SwiftUISample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftUISample.entitlements; sourceTree = ""; }; 5134F870277EAF1600AEE915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUISample.release.xcconfig"; path = "Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,18 +40,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CD7B98AE712C5BD92A57F49B /* Pods_SwiftUISample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4B9D6C361383C06EE523D776 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 5134F853277EAEC600AEE915 = { isa = PBXGroup; children = ( 5134F85E277EAEC600AEE915 /* SwiftUISample */, 5134F85D277EAEC600AEE915 /* Products */, A18B84A7C0849ACD661DA216 /* Pods */, + 4B9D6C361383C06EE523D776 /* Frameworks */, ); sourceTree = ""; }; @@ -87,6 +101,8 @@ A18B84A7C0849ACD661DA216 /* Pods */ = { isa = PBXGroup; children = ( + 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */, + 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -98,9 +114,11 @@ isa = PBXNativeTarget; buildConfigurationList = 5134F86A277EAEC900AEE915 /* Build configuration list for PBXNativeTarget "SwiftUISample" */; buildPhases = ( + FB277254786D33A1256CB1E5 /* [CP] Check Pods Manifest.lock */, 5134F858277EAEC600AEE915 /* Sources */, 5134F859277EAEC600AEE915 /* Frameworks */, 5134F85A277EAEC600AEE915 /* Resources */, + 87E3D238B4B412EC4E446F6E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -157,6 +175,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 87E3D238B4B412EC4E446F6E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FB277254786D33A1256CB1E5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SwiftUISample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 5134F858277EAEC600AEE915 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -291,6 +351,7 @@ }; 5134F86B277EAEC900AEE915 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -325,6 +386,7 @@ }; 5134F86C277EAEC900AEE915 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; From f8758eba63fa58eab05cf8fdd22649528081c059 Mon Sep 17 00:00:00 2001 From: Visu Date: Thu, 14 Nov 2024 09:48:09 -0800 Subject: [PATCH 39/98] Fix a crash that happens when the application changes states. (#14102) --- FirebasePerformance/CHANGELOG.md | 3 ++ .../FPRTraceBackgroundActivityTracker.m | 19 +++---- .../FPRTraceBackgroundActivityTrackerTest.m | 24 +++++++-- .../Tests/Unit/Timer/FIRTraceTest.m | 51 ++++++++++++++----- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/FirebasePerformance/CHANGELOG.md b/FirebasePerformance/CHANGELOG.md index fd98d461eee..a5679e943cc 100644 --- a/FirebasePerformance/CHANGELOG.md +++ b/FirebasePerformance/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fix a crash related to registering for notifications when the app is between foreground or background states. (#13174) + # 11.5.0 - [fixed] Replaced usage of the deprecated `UIApplication.keyWindow` property with `UIWindow.isKeyWindow`; this API is also available on visionOS. Note that diff --git a/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m b/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m index f7608fd9d96..5c7db89c9fe 100644 --- a/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m +++ b/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m @@ -35,16 +35,17 @@ - (instancetype)init { } else { _traceBackgroundState = FPRTraceStateForegroundOnly; } + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidBecomeActive:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidBecomeActive:) - name:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidEnterBackground:) - name:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + }); } return self; } diff --git a/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m b/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m index ab5268f3f00..272a7c418fa 100644 --- a/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m +++ b/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m @@ -38,13 +38,27 @@ - (void)testForegroundTracking { /** Validates if the foreground & background state is captured correctly. */ - (void)testBackgroundTracking { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; + FPRTraceBackgroundActivityTracker *tracker = [[FPRTraceBackgroundActivityTracker alloc] init]; NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - XCTAssertEqual(tracker.traceBackgroundState, FPRTraceStateBackgroundAndForeground); + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + XCTAssertEqual(tracker.traceBackgroundState, + FPRTraceStateBackgroundAndForeground); + } + }]; } @end diff --git a/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m b/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m index bd187089d16..39a389fdb3b 100644 --- a/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m +++ b/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m @@ -427,15 +427,28 @@ - (void)testValidTraceWithStageAndMetrics { /** Validates the value of background state when the app is backgrounded. */ - (void)testValidTraceWithBackgrounding { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; FIRTrace *trace = [[FIRTrace alloc] initWithName:@"Random"]; [trace start]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - XCTAssertEqual(trace.backgroundTraceState, FPRTraceStateBackgroundAndForeground); - [trace stop]; + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + XCTAssertEqual(trace.backgroundTraceState, + FPRTraceStateBackgroundAndForeground); + [trace stop]; + } + }]; } /** Validates the value of background state when trace is not started. */ @@ -452,15 +465,29 @@ - (void)testValidTraceWithoutStart { /** Validates the value of background state is available after trace is stopped. */ - (void)testBackgroundStateAfterTraceStop { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; FIRTrace *trace = [[FIRTrace alloc] initWithName:@"Random"]; [trace start]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - [trace stop]; - XCTAssertEqual(trace.backgroundTraceState, FPRTraceStateBackgroundAndForeground); + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + [trace stop]; + XCTAssertEqual(trace.backgroundTraceState, + FPRTraceStateBackgroundAndForeground); + } + }]; } /** Validates that stages do not have any valid background state. */ From e4bc4452ac285e699022921a3c4a39ad61c11a48 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 14 Nov 2024 13:07:50 -0500 Subject: [PATCH 40/98] [Infra] Switch to iPhone 15 simulator in build_with_environment.sh (#14123) --- .../scripts/build_with_environment.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh b/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh index 1c45d2521fd..10900343894 100755 --- a/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh +++ b/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh @@ -27,7 +27,7 @@ function runXcodebuild() { -workspace 'CocoapodsIntegrationTest.xcworkspace' -scheme 'CocoapodsIntegrationTest' -sdk 'iphonesimulator' - -destination 'platform=iOS Simulator,name=iPhone 14' + -destination 'platform=iOS Simulator,name=iPhone 15' CODE_SIGNING_REQUIRED=NO clean build @@ -36,7 +36,7 @@ function runXcodebuild() { parameters=("${buildcache_xcb_flags[@]}" "${parameters[@]}") echo xcodebuild "${parameters[@]}" - xcodebuild "${parameters[@]}" | xcpretty; result=$? + xcodebuild "${parameters[@]}" | xcbeautify --renderer github-actions; result=$? } # Configures bundler environment using Gemfile at the specified path. From bda2be9b913380290a8d21355eff544a8b0569bd Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:22:42 -0500 Subject: [PATCH 41/98] [Auth] Remove AuthDispatcher singleton, prefer DI (#14122) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 8 ++++++-- .../Sources/Swift/Auth/AuthDispatcher.swift | 12 ++++++++---- .../Tests/Unit/AuthDispatcherTests.swift | 16 ++-------------- FirebaseAuth/Tests/Unit/AuthTests.swift | 16 ++++++++-------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index e5ccdaafac7..f77fe2aae2c 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -1616,7 +1616,8 @@ extension Auth: AuthInterop { init(app: FirebaseApp, keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal(), - backend: AuthBackend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer())) { + backend: AuthBackend = .init(rpcIssuer: AuthBackendRPCIssuer()), + authDispatcher: AuthDispatcher = .init()) { Auth.setKeychainServiceNameForApp(app) self.app = app mainBundleUrlTypes = Bundle.main @@ -1642,6 +1643,7 @@ extension Auth: AuthInterop { heartbeatLogger: app.heartbeatLogger, appCheck: appCheck) self.backend = backend + self.authDispatcher = authDispatcher super.init() requestConfiguration.auth = self @@ -1902,7 +1904,7 @@ extension Auth: AuthInterop { } autoRefreshScheduled = true weak var weakSelf = self - AuthDispatcher.shared.dispatch(afterDelay: delay, queue: kAuthGlobalWorkQueue) { + authDispatcher.dispatch(afterDelay: delay, queue: kAuthGlobalWorkQueue) { guard let strongSelf = weakSelf else { return } @@ -2361,6 +2363,8 @@ extension Auth: AuthInterop { /// The Firebase app name. private let firebaseAppName: String + private let authDispatcher: AuthDispatcher + /// The keychain service. private var keychainServices: AuthKeychainServices! diff --git a/FirebaseAuth/Sources/Swift/Auth/AuthDispatcher.swift b/FirebaseAuth/Sources/Swift/Auth/AuthDispatcher.swift index 6373cdfb4cc..f25e256ad51 100644 --- a/FirebaseAuth/Sources/Swift/Auth/AuthDispatcher.swift +++ b/FirebaseAuth/Sources/Swift/Auth/AuthDispatcher.swift @@ -15,13 +15,17 @@ import Foundation /// A utility class used to facilitate scheduling tasks to be executed in the future. -class AuthDispatcher { - static let shared = AuthDispatcher() - +struct AuthDispatcher { /// Allows custom implementation of dispatchAfterDelay:queue:callback:. /// /// Set to nil to restore default implementation. - var dispatchAfterImplementation: ((TimeInterval, DispatchQueue, @escaping () -> Void) -> Void)? + private let dispatchAfterImplementation: ((TimeInterval, DispatchQueue, @escaping () -> Void) + -> Void)? + + init(dispatchAfterImplementation: ((TimeInterval, DispatchQueue, @escaping () -> Void) -> Void)? = + nil) { + self.dispatchAfterImplementation = dispatchAfterImplementation + } /// Schedules task in the future after a specified delay. /// - Parameter delay: The delay in seconds after which the task will be scheduled to execute. diff --git a/FirebaseAuth/Tests/Unit/AuthDispatcherTests.swift b/FirebaseAuth/Tests/Unit/AuthDispatcherTests.swift index 08f34585ba0..57dc9e394c9 100644 --- a/FirebaseAuth/Tests/Unit/AuthDispatcherTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthDispatcherTests.swift @@ -22,25 +22,15 @@ class AuthDispatcherTests: XCTestCase { let kTestDelay = 0.1 let kMaxDifferenceBetweenTimeIntervals = 0.4 - /** @fn testSharedInstance - @brief Tests @c sharedInstance returns the same object. - */ - func testSharedInstance() { - let instance1 = AuthDispatcher.shared - let instance2 = AuthDispatcher.shared - XCTAssert(instance1 === instance2) - } - /** @fn testDispatchAfterDelay @brief Tests @c dispatchAfterDelay indeed dispatches the specified task after the provided delay. */ func testDispatchAfterDelay() { - let dispatcher = AuthDispatcher.shared + let dispatcher = AuthDispatcher() let testWorkQueue = DispatchQueue(label: "test.work.queue") let expectation = self.expectation(description: #function) let dateBeforeDispatch = Date() - dispatcher.dispatchAfterImplementation = nil dispatcher.dispatch(afterDelay: kTestDelay, queue: testWorkQueue) { [self] in let timeSinceDispatch = fabs(dateBeforeDispatch.timeIntervalSinceNow - self.kTestDelay) XCTAssertLessThan(timeSinceDispatch, kMaxDifferenceBetweenTimeIntervals) @@ -54,15 +44,13 @@ class AuthDispatcherTests: XCTestCase { @c dispatchAfterDelay. */ func testSetDispatchAfterImplementation() { - let dispatcher = AuthDispatcher.shared let testWorkQueue = DispatchQueue(label: "test.work.queue") let expectation = self.expectation(description: #function) - dispatcher.dispatchAfterImplementation = { delay, queue, task in + let dispatcher = AuthDispatcher { delay, queue, task in XCTAssertEqual(self.kTestDelay, delay) XCTAssertEqual(testWorkQueue, queue) expectation.fulfill() } - dispatcher.dispatch(afterDelay: kTestDelay, queue: testWorkQueue) { // Fail to ensure this code is never executed. XCTFail("Should not execute this code") diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index f84eb33d70f..9bf57b39dd3 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -45,20 +45,20 @@ class AuthTests: RPCBaseTests { #else let keychainStorageProvider = AuthKeychainStorageReal() #endif // (os(macOS) && !FIREBASE_AUTH_TESTING_USE_MACOS_KEYCHAIN) || SWIFT_PACKAGE - auth = Auth( - app: FirebaseApp.app(name: name)!, - keychainStorageProvider: keychainStorageProvider, - backend: authBackend - ) - // Set authDispatcherCallback implementation in order to save the token refresh task for later - // execution. - AuthDispatcher.shared.dispatchAfterImplementation = { delay, queue, task in + // Stub the implementation to save the token refresh task for later execution. + let authDispatcher = AuthDispatcher { delay, queue, task in XCTAssertNotNil(task) XCTAssertGreaterThan(delay, 0) XCTAssertEqual(kAuthGlobalWorkQueue, queue) self.authDispatcherCallback = task } + auth = Auth( + app: FirebaseApp.app(name: name)!, + keychainStorageProvider: keychainStorageProvider, + backend: authBackend, + authDispatcher: authDispatcher + ) // Wait until Auth initialization completes waitForAuthGlobalWorkQueueDrain() } From b91dfda0264195cfa47c0dea3b08f2184327c4d0 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 14 Nov 2024 14:18:49 -0500 Subject: [PATCH 42/98] [Infra] Update workflows from Python 3.10 to 3.11 (#14121) --- .github/workflows/api_diff_report.yml | 2 +- .github/workflows/firestore.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/api_diff_report.yml b/.github/workflows/api_diff_report.yml index 1e5f18a15b9..afdae6c95c7 100644 --- a/.github/workflows/api_diff_report.yml +++ b/.github/workflows/api_diff_report.yml @@ -36,7 +36,7 @@ jobs: - name: Setup python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' - name: Install Prerequisites run: ~/api_diff_report/prerequisite.sh diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index e57cb9d7088..72d14573a8a 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -130,7 +130,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake @@ -180,7 +180,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' - name: Install Secret GoogleService-Info.plist run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore.plist.gpg \ @@ -259,7 +259,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.11' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake From ec3386a600ee88138bdba83ca3d668ac631e5d5f Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 14 Nov 2024 18:20:18 -0500 Subject: [PATCH 43/98] [Infra] Exclude pods that aren't releasing in GHAMatrixSpecCollector (#14119) --- .github/workflows/cocoapods-integration.yml | 1 + .github/workflows/notice_generation.yml | 2 +- .github/workflows/release.yml | 2 +- .../Sources/ManifestParser/GHAMatrixSpecCollector.swift | 3 +-- ReleaseTooling/Sources/ManifestParser/main.swift | 9 ++------- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/cocoapods-integration.yml b/.github/workflows/cocoapods-integration.yml index bd82129d66f..0e08b9a3a6f 100644 --- a/.github/workflows/cocoapods-integration.yml +++ b/.github/workflows/cocoapods-integration.yml @@ -18,6 +18,7 @@ jobs: tests: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' + || github.event_name == 'workflow_dispatch' runs-on: macos-14 steps: diff --git a/.github/workflows/notice_generation.yml b/.github/workflows/notice_generation.yml index 579db732cbc..58f9a4345b8 100644 --- a/.github/workflows/notice_generation.yml +++ b/.github/workflows/notice_generation.yml @@ -11,7 +11,7 @@ on: jobs: generate_a_notice: # Don't run on private repo. - if: github.repository == 'Firebase/firebase-ios-sdk' + if: github.repository == 'Firebase/firebase-ios-sdk' || github.event_name == 'workflow_dispatch' runs-on: macos-14 name: Generate NOTICES env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d934918c71..3722efa96da 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,7 +107,7 @@ jobs: buildup_SpecsReleasing_repo: needs: [buildup_SpecsReleasing_repo_FirebaseCore, specs_checking] # Don't run on private repo unless it is a PR. - if: github.repository == 'Firebase/firebase-ios-sdk' + if: github.repository == 'Firebase/firebase-ios-sdk' || github.event_name == 'workflow_dispatch' runs-on: macos-14 strategy: fail-fast: false diff --git a/ReleaseTooling/Sources/ManifestParser/GHAMatrixSpecCollector.swift b/ReleaseTooling/Sources/ManifestParser/GHAMatrixSpecCollector.swift index 40541c73ff2..fd942698c4c 100644 --- a/ReleaseTooling/Sources/ManifestParser/GHAMatrixSpecCollector.swift +++ b/ReleaseTooling/Sources/ManifestParser/GHAMatrixSpecCollector.swift @@ -31,11 +31,10 @@ struct SDKPodspec: Codable { struct GHAMatrixSpecCollector { var SDKRepoURL: URL var outputSpecFileURL: URL - var excludedSDKs: [String] = [] func getPodsInManifest(_ manifest: Manifest) -> [String: SDKPodspec] { var podsMap: [String: SDKPodspec] = [:] - for pod in manifest.pods { + for pod in manifest.pods.filter({ $0.releasing }) { podsMap[pod.name] = SDKPodspec(podspec: pod.name, allowWarnings: pod.allowWarnings) } return podsMap diff --git a/ReleaseTooling/Sources/ManifestParser/main.swift b/ReleaseTooling/Sources/ManifestParser/main.swift index a6d976a0f21..88cd76159f0 100644 --- a/ReleaseTooling/Sources/ManifestParser/main.swift +++ b/ReleaseTooling/Sources/ManifestParser/main.swift @@ -42,15 +42,12 @@ struct ManifestParser: ParsableCommand { }) var outputFilePath: URL - @Option(parsing: .upToNextOption, help: "Podspec files that will not be included.") - var excludedSpecs: [String] - @Flag(help: "Parsing mode for manifest") var mode: ParsingMode func parsePodNames(_ manifest: Manifest) throws { var output: [String] = [] - for pod in manifest.pods { + for pod in manifest.pods.filter({ $0.releasing }) { output.append(pod.name) } do { @@ -69,9 +66,7 @@ struct ManifestParser: ParsableCommand { try parsePodNames(FirebaseManifest.shared) case .forGHAMatrixGeneration: guard let sdkRepoURL = SDKRepoURL else { - throw fatalError( - "--sdk-repo-url should be specified when --for-gha-matrix-generation is on." - ) + fatalError("--sdk-repo-url should be specified when --for-gha-matrix-generation is on.") } let specCollector = GHAMatrixSpecCollector( SDKRepoURL: sdkRepoURL, From 427647b051ef1cda2aa0e2f8ac264dfbb4b701b6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 15 Nov 2024 10:11:02 -0500 Subject: [PATCH 44/98] [Auth] Make AuthBackend and related types Sendable (#14125) --- .../Sources/Swift/Backend/AuthBackend.swift | 4 ++-- .../Swift/Backend/AuthBackendRPCIssuer.swift | 8 ++++---- .../Tests/Unit/Fakes/FakeBackendRPCIssuer.swift | 17 ++++++++--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 85802392052..474f665147f 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -22,12 +22,12 @@ import Foundation #endif @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -protocol AuthBackendProtocol { +protocol AuthBackendProtocol: Sendable { func call(with request: T) async throws -> T.Response } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class AuthBackend: AuthBackendProtocol { +final class AuthBackend: AuthBackendProtocol { static func authUserAgent() -> String { return "FirebaseAuth.iOS/\(FirebaseVersion()) \(GTMFetcherStandardUserAgentString(nil))" } diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift index 01001c5d712..6d2c540ff37 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift @@ -16,13 +16,13 @@ import FirebaseCore import FirebaseCoreExtension import Foundation #if COCOAPODS - import GTMSessionFetcher + @preconcurrency import GTMSessionFetcher #else - import GTMSessionFetcherCore + @preconcurrency import GTMSessionFetcherCore #endif @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -protocol AuthBackendRPCIssuerProtocol { +protocol AuthBackendRPCIssuerProtocol: Sendable { /// Asynchronously send a HTTP request. /// - Parameter request: The request to be made. /// - Parameter body: Request body. @@ -35,7 +35,7 @@ protocol AuthBackendRPCIssuerProtocol { } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class AuthBackendRPCIssuer: AuthBackendRPCIssuerProtocol { +final class AuthBackendRPCIssuer: AuthBackendRPCIssuerProtocol { let fetcherService: GTMSessionFetcherService init() { diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift index e09e8d2106c..3a40aac37d7 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift @@ -17,13 +17,12 @@ import XCTest @testable import FirebaseAuth -// TODO: Investigate making this class support generics for the `request`. -/** @class FakeBackendRPCIssuer - @brief An implementation of @c AuthBackendRPCIssuer which is used to test backend request, - response, and glue logic. - */ +// TODO(ncooke3): Investigate making this class support generics for the `request`. +// TODO(ncooke3): Refactor to make checked Sendable. +/// An implementation of `AuthBackendRPCIssuerProtocol` which is used to test +/// backend request, response, and glue logic. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class FakeBackendRPCIssuer: AuthBackendRPCIssuer { +final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Sendable { /** @property requestURL @brief The URL which was requested. */ @@ -77,8 +76,8 @@ class FakeBackendRPCIssuer: AuthBackendRPCIssuer { var secureTokenErrorString: String? var recaptchaSiteKey = "unset recaptcha siteKey" - override func asyncCallToURL(with request: T, body: Data?, - contentType: String) async -> (Data?, Error?) + func asyncCallToURL(with request: T, body: Data?, + contentType: String) async -> (Data?, Error?) where T: FirebaseAuth.AuthRPCRequest { return await withCheckedContinuation { continuation in self.asyncCallToURL(with: request, body: body, contentType: contentType) { data, error in @@ -172,7 +171,7 @@ class FakeBackendRPCIssuer: AuthBackendRPCIssuer { } func respond(serverErrorMessage errorMessage: String, error: NSError) throws { - let _ = try respond(withJSON: ["error": ["message": errorMessage]], error: error) + _ = try respond(withJSON: ["error": ["message": errorMessage]], error: error) } @discardableResult func respond(underlyingErrorMessage errorMessage: String, From b1b7807c381e3563e8145a62220d8ffb7af6d1a1 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:03:27 -0500 Subject: [PATCH 45/98] [Infra] Run Auth QS with Xcode 16 to resolve Facebook SDK breaking change (#14129) --- .github/workflows/prerelease.yml | 4 +++- .github/workflows/release.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index a56f44ba74c..c3f3ba9f782 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -247,13 +247,15 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} bot_token_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Get token run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/prerelease-testing-token.txt.gpg \ bot-access.txt "$bot_token_secret" + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer - name: Setup testing repo and quickstart run: | botaccess=`cat bot-access.txt` diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3722efa96da..c092b86a9e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -195,13 +195,15 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} bot_token_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 - name: Get token run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/release-testing-token.txt.gpg \ bot-access.txt "$bot_token_secret" + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer - name: Setup testing repo and quickstart run: | botaccess=`cat bot-access.txt` From f9817995169e2157f2a30a54ce89ab712bc3bf0d Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:49:56 -0500 Subject: [PATCH 46/98] [Infra] Migrate away from macos-12 in sessions-integration-tests.yml (#14130) --- .github/workflows/sessions-integration-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/sessions-integration-tests.yml b/.github/workflows/sessions-integration-tests.yml index a018edcddcc..d24f83a4955 100644 --- a/.github/workflows/sessions-integration-tests.yml +++ b/.github/workflows/sessions-integration-tests.yml @@ -26,8 +26,7 @@ jobs: if: github.repository == 'Firebase/firebase-ios-sdk' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - #TODO(#12771): Fix macos-14 build issues - runs-on: macos-12 + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 From 15caf49aad94dba356070990256b920840fc905d Mon Sep 17 00:00:00 2001 From: Yakov Manshin Date: Mon, 18 Nov 2024 16:13:07 +0100 Subject: [PATCH 47/98] Switched `HTTPSCallable` to Async Method (#14085) --- FirebaseFunctions/Sources/HTTPSCallable.swift | 38 ++++++++++++------- .../CombineUnit/HTTPSCallableTests.swift | 9 +++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/FirebaseFunctions/Sources/HTTPSCallable.swift b/FirebaseFunctions/Sources/HTTPSCallable.swift index 2c772bc8c78..c2281e54866 100644 --- a/FirebaseFunctions/Sources/HTTPSCallable.swift +++ b/FirebaseFunctions/Sources/HTTPSCallable.swift @@ -78,22 +78,32 @@ open class HTTPSCallable: NSObject { @objc(callWithObject:completion:) open func call(_ data: Any? = nil, completion: @escaping (HTTPSCallableResult?, Error?) -> Void) { - let callback: ((Result) -> Void) = { result in - switch result { - case let .success(callableResult): - completion(callableResult, nil) - case let .failure(error): - completion(nil, error) + if #available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) { + Task { + do { + let result = try await call(data) + completion(result, nil) + } catch { + completion(nil, error) + } + } + } else { + // This isn’t expected to ever be called because Functions + // doesn’t officially support the older platforms. + functions.callFunction( + at: url, + withObject: data, + options: options, + timeout: timeoutInterval + ) { result in + switch result { + case let .success(callableResult): + completion(callableResult, nil) + case let .failure(error): + completion(nil, error) + } } } - - functions.callFunction( - at: url, - withObject: data, - options: options, - timeout: timeoutInterval, - completion: callback - ) } /// Executes this Callable HTTPS trigger asynchronously. This API should only be used from diff --git a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift index 8ed63c344b7..3c1399ad522 100644 --- a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift +++ b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift @@ -31,6 +31,15 @@ private let expectationTimeout: TimeInterval = 2 class MockFunctions: Functions { let mockCallFunction: () throws -> HTTPSCallableResult var verifyParameters: ((_ url: URL, _ data: Any?, _ timeout: TimeInterval) throws -> Void)? + + override func callFunction(at url: URL, + withObject data: Any?, + options: HTTPSCallableOptions?, + timeout: TimeInterval) async throws -> HTTPSCallableResult { + try verifyParameters?(url, data, timeout) + return try mockCallFunction() + } + override func callFunction(at url: URL, withObject data: Any?, options: HTTPSCallableOptions?, From 56d4c183875549ccc933814f42ca51a2a351f1f1 Mon Sep 17 00:00:00 2001 From: Yakov Manshin Date: Mon, 18 Nov 2024 16:20:38 +0100 Subject: [PATCH 48/98] =?UTF-8?q?Refactored=20`Functions`=E2=80=99s=20Resu?= =?UTF-8?q?lt=20Handling=20(#14086)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FirebaseFunctions/Sources/Functions.swift | 68 +++++++++++------------ 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/FirebaseFunctions/Sources/Functions.swift b/FirebaseFunctions/Sources/Functions.swift index d4cd4e4f54f..51e405b2f39 100644 --- a/FirebaseFunctions/Sources/Functions.swift +++ b/FirebaseFunctions/Sources/Functions.swift @@ -401,11 +401,9 @@ enum FunctionsConstants { do { let rawData = try await fetcher.beginFetch() - return try callableResultFromResponse(data: rawData, error: nil) + return try callableResult(fromResponseData: rawData) } catch { - // This method always throws when `error` is not `nil`, but ideally, - // it should be refactored so it looks less confusing. - return try callableResultFromResponse(data: nil, error: error) + throw processedError(fromResponseError: error) } } @@ -455,10 +453,16 @@ enum FunctionsConstants { fetcher.beginFetch { [self] data, error in let result: Result - do { - result = try .success(callableResultFromResponse(data: data, error: error)) - } catch { - result = .failure(error) + if let error { + result = .failure(processedError(fromResponseError: error)) + } else if let data { + do { + result = try .success(callableResult(fromResponseData: data)) + } catch { + result = .failure(error) + } + } else { + result = .failure(FunctionsError(.internal)) } DispatchQueue.main.async { @@ -519,9 +523,23 @@ enum FunctionsConstants { return fetcher } - private func callableResultFromResponse(data: Data?, - error: (any Error)?) throws -> HTTPSCallableResult { - let processedData = try processedResponseData(from: data, error: error) + private func processedError(fromResponseError error: any Error) -> any Error { + let error = error as NSError + let localError: (any Error)? = if error.domain == kGTMSessionFetcherStatusDomain { + FunctionsError( + httpStatusCode: error.code, + body: error.userInfo["data"] as? Data, + serializer: serializer + ) + } else if error.domain == NSURLErrorDomain, error.code == NSURLErrorTimedOut { + FunctionsError(.deadlineExceeded) + } else { nil } + + return localError ?? error + } + + private func callableResult(fromResponseData data: Data) throws -> HTTPSCallableResult { + let processedData = try processedData(fromResponseData: data) let json = try responseDataJSON(from: processedData) // TODO: Refactor `decode(_:)` so it either returns a non-optional object or throws let payload = try serializer.decode(json) @@ -529,36 +547,12 @@ enum FunctionsConstants { return HTTPSCallableResult(data: payload as Any) } - private func processedResponseData(from data: Data?, error: (any Error)?) throws -> Data { - // Case 1: `error` is not `nil` -> always throws - if let error = error as NSError? { - let localError: (any Error)? - if error.domain == kGTMSessionFetcherStatusDomain { - localError = FunctionsError( - httpStatusCode: error.code, - body: data ?? error.userInfo["data"] as? Data, - serializer: serializer - ) - } else if error.domain == NSURLErrorDomain, error.code == NSURLErrorTimedOut { - localError = FunctionsError(.deadlineExceeded) - } else { - localError = nil - } - - throw localError ?? error - } - - // Case 2: `data` is `nil` -> always throws - guard let data else { - throw FunctionsError(.internal) - } - - // Case 3: `data` is not `nil` but might specify a custom error -> throws conditionally + private func processedData(fromResponseData data: Data) throws -> Data { + // `data` might specify a custom error. If so, throw the error. if let bodyError = FunctionsError(httpStatusCode: 200, body: data, serializer: serializer) { throw bodyError } - // Case 4: `error` is `nil`; `data` is not `nil`; `data` doesn’t specify an error -> OK return data } From 3efb024df33a7bbe211eaaae46bb33cd309f4db4 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:21:23 -0500 Subject: [PATCH 49/98] [Auth] Get 'currentUser' on Auth worker queue (#14141) --- FirebaseAuth/CHANGELOG.md | 5 +++ FirebaseAuth/Sources/Swift/Auth/Auth.swift | 46 ++++++++++++---------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index c627b29eed5..36eca32322a 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,8 @@ +# Unreleased +- [fixed] Restore Firebase 10 behavior by synchronizing access to the + `Auth.currentUser` API. This resolves some Firebase 11 issues where the + current user is unexpectedly `nil` at startup. + # 11.5.0 - [fixed] Restore pre-Firebase 11 decoding behavior to prevent users getting logged out when upgrading from Firebase 8.10.0 or earlier to Firebase 11. diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index f77fe2aae2c..de7ea8e8add 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -116,7 +116,7 @@ extension Auth: AuthInterop { } } // Call back with 'nil' if there is no current user. - guard let strongSelf = self, let currentUser = strongSelf.currentUser else { + guard let strongSelf = self, let currentUser = strongSelf._currentUser else { DispatchQueue.main.async { callback(nil, nil) } @@ -136,7 +136,7 @@ extension Auth: AuthInterop { /// /// This method is not for public use. It is for Firebase clients of AuthInterop. open func getUserID() -> String? { - return currentUser?.uid + return _currentUser?.uid } } @@ -170,7 +170,13 @@ extension Auth: AuthInterop { @objc public internal(set) weak var app: FirebaseApp? /// Synchronously gets the cached current user, or null if there is none. - @objc public internal(set) var currentUser: User? + @objc public var currentUser: User? { + kAuthGlobalWorkQueue.sync { + _currentUser + } + } + + private var _currentUser: User? /// The current user language code. /// @@ -702,7 +708,7 @@ extension Auth: AuthInterop { @objc open func signInAnonymously(completion: ((AuthDataResult?, Error?) -> Void)? = nil) { kAuthGlobalWorkQueue.async { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) - if let currentUser = self.currentUser, currentUser.isAnonymous { + if let currentUser = self._currentUser, currentUser.isAnonymous { let result = AuthDataResult(withUser: currentUser, additionalUserInfo: nil) decoratedCallback(result, nil) return @@ -1264,7 +1270,7 @@ extension Auth: AuthInterop { /// dictionary will contain more information about the error encountered. @objc(signOut:) open func signOut() throws { try kAuthGlobalWorkQueue.sync { - guard self.currentUser != nil else { + guard self._currentUser != nil else { return } return try self.updateCurrentUser(nil, byForce: false, savingToDisk: true) @@ -1385,14 +1391,14 @@ extension Auth: AuthInterop { queue: OperationQueue.main ) { notification in if let auth = notification.object as? Auth { - listener(auth, auth.currentUser) + listener(auth, auth._currentUser) } } objc_sync_enter(Auth.self) listenerHandles.add(listener) objc_sync_exit(Auth.self) DispatchQueue.main.async { - listener(self, self.currentUser) + listener(self, self._currentUser) } return handle } @@ -1434,7 +1440,7 @@ extension Auth: AuthInterop { /// complete, or fails. Invoked asynchronously on the main thread in the future. @objc open func revokeToken(withAuthorizationCode authorizationCode: String, completion: ((Error?) -> Void)? = nil) { - currentUser?.internalGetToken(backend: backend) { idToken, error in + _currentUser?.internalGetToken(backend: backend) { idToken, error in if let error { Auth.wrapMainAsync(completion, error) return @@ -1790,7 +1796,7 @@ extension Auth: AuthInterop { } func updateKeychain(withUser user: User?) -> Error? { - if user != currentUser { + if user != _currentUser { // No-op if the user is no longer signed in. This is not considered an error as we don't check // whether the user is still current on other callbacks of user operations either. return nil @@ -1836,7 +1842,7 @@ extension Auth: AuthInterop { } func signOutByForce(withUserID userID: String) throws { - guard currentUser?.uid == userID else { + guard _currentUser?.uid == userID else { return } try updateCurrentUser(nil, byForce: true, savingToDisk: true) @@ -1846,7 +1852,7 @@ extension Auth: AuthInterop { /// Posts the auth state change notification if current user's token has been changed. private func possiblyPostAuthStateChangeNotification() { - let token = currentUser?.rawAccessToken() + let token = _currentUser?.rawAccessToken() if lastNotifiedUserToken == token || (token != nil && lastNotifiedUserToken == token) { return @@ -1863,7 +1869,7 @@ extension Auth: AuthInterop { if let token, token.count > 0 { internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationTokenKey] = token } - internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationUIDKey] = currentUser? + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationUIDKey] = _currentUser? .uid let notifications = NotificationCenter.default DispatchQueue.main.async { @@ -1880,7 +1886,7 @@ extension Auth: AuthInterop { /// If the token expires in less than 5 minutes, schedule the token refresh immediately. private func scheduleAutoTokenRefresh() { let tokenExpirationInterval = - (currentUser?.accessTokenExpirationDate()?.timeIntervalSinceNow ?? 0) - 5 * 60 + (_currentUser?.accessTokenExpirationDate()?.timeIntervalSinceNow ?? 0) - 5 * 60 scheduleAutoTokenRefresh(withDelay: max(tokenExpirationInterval, 0), retry: false) } @@ -1889,7 +1895,7 @@ extension Auth: AuthInterop { /// to be executed. /// - Parameter retry: Flag to determine whether the invocation is a retry attempt or not. private func scheduleAutoTokenRefresh(withDelay delay: TimeInterval, retry: Bool) { - guard let accessToken = currentUser?.rawAccessToken() else { + guard let accessToken = _currentUser?.rawAccessToken() else { return } let intDelay = Int(ceil(delay)) @@ -1908,7 +1914,7 @@ extension Auth: AuthInterop { guard let strongSelf = weakSelf else { return } - guard strongSelf.currentUser?.rawAccessToken() == accessToken else { + guard strongSelf._currentUser?.rawAccessToken() == accessToken else { // Another auto refresh must have been scheduled, so keep _autoRefreshScheduled unchanged. return } @@ -1916,10 +1922,10 @@ extension Auth: AuthInterop { if strongSelf.isAppInBackground { return } - let uid = strongSelf.currentUser?.uid - strongSelf.currentUser? + let uid = strongSelf._currentUser?.uid + strongSelf._currentUser? .internalGetToken(forceRefresh: true, backend: strongSelf.backend) { token, error in - if strongSelf.currentUser?.uid != uid { + if strongSelf._currentUser?.uid != uid { return } if error != nil { @@ -1943,7 +1949,7 @@ extension Auth: AuthInterop { /// - Parameter saveToDisk: Indicates the method should persist the user data to disk. func updateCurrentUser(_ user: User?, byForce force: Bool, savingToDisk saveToDisk: Bool) throws { - if user == currentUser { + if user == _currentUser { possiblyPostAuthStateChangeNotification() } if let user { @@ -1960,7 +1966,7 @@ extension Auth: AuthInterop { } } if throwError == nil || force { - currentUser = user + _currentUser = user possiblyPostAuthStateChangeNotification() } if let throwError { From 2495c2019d097ba3a58525e4d1556e1787477fb2 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:24:13 -0500 Subject: [PATCH 50/98] [Auth] Schedule keychain access after prewarming (#14142) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 68 ++++++++++--------- .../Sources/Swift/Auth/AuthComponent.swift | 3 +- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index de7ea8e8add..3600a90c478 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -1624,7 +1624,6 @@ extension Auth: AuthInterop { keychainStorageProvider: AuthKeychainStorage = AuthKeychainStorageReal(), backend: AuthBackend = .init(rpcIssuer: AuthBackendRPCIssuer()), authDispatcher: AuthDispatcher = .init()) { - Auth.setKeychainServiceNameForApp(app) self.app = app mainBundleUrlTypes = Bundle.main .object(forInfoDictionaryKey: "CFBundleURLTypes") as? [[String: Any]] @@ -1650,27 +1649,28 @@ extension Auth: AuthInterop { appCheck: appCheck) self.backend = backend self.authDispatcher = authDispatcher + + let keychainServiceName = Auth.keychainServiceName(for: app) + keychainServices = AuthKeychainServices(service: keychainServiceName, + storage: keychainStorageProvider) + storedUserManager = AuthStoredUserManager( + serviceName: keychainServiceName, + keychainServices: keychainServices + ) + super.init() requestConfiguration.auth = self - protectedDataInitialization(keychainStorageProvider) + protectedDataInitialization() } - private func protectedDataInitialization(_ keychainStorageProvider: AuthKeychainStorage) { + private func protectedDataInitialization() { // Continue with the rest of initialization in the work thread. kAuthGlobalWorkQueue.async { [weak self] in // Load current user from Keychain. guard let self else { return } - if let keychainServiceName = Auth.keychainServiceName(forAppName: self.firebaseAppName) { - self.keychainServices = AuthKeychainServices(service: keychainServiceName, - storage: keychainStorageProvider) - self.storedUserManager = AuthStoredUserManager( - serviceName: keychainServiceName, - keychainServices: self.keychainServices - ) - } do { if let storedUserAccessGroup = self.storedUserManager.getStoredUserAccessGroup() { @@ -1729,21 +1729,21 @@ extension Auth: AuthInterop { #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) private func addProtectedDataDidBecomeAvailableObserver() { - weak var weakSelf = self protectedDataDidBecomeAvailableObserver = NotificationCenter.default.addObserver( forName: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil, queue: nil - ) { notification in - let strongSelf = weakSelf - if let observer = strongSelf?.protectedDataDidBecomeAvailableObserver { + ) { [weak self] notification in + guard let self else { return } + if let observer = self.protectedDataDidBecomeAvailableObserver { NotificationCenter.default.removeObserver( observer, name: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil ) } + self.protectedDataInitialization() } } #endif @@ -1817,28 +1817,34 @@ extension Auth: AuthInterop { /// @synchronized([FIRAuth class]) context. fileprivate static var gKeychainServiceNameForAppName: [String: String] = [:] - /// Sets the keychain service name global data for the particular app. - /// - Parameter app: The Firebase app to set keychain service name for. - class func setKeychainServiceNameForApp(_ app: FirebaseApp) { - objc_sync_enter(Auth.self) - gKeychainServiceNameForAppName[app.name] = "firebase_auth_\(app.options.googleAppID)" - objc_sync_exit(Auth.self) - } - - /// Gets the keychain service name global data for the particular app by name. - /// - Parameter appName: The name of the Firebase app to get keychain service name for. - class func keychainServiceName(forAppName appName: String) -> String? { + /// Gets the keychain service name global data for the particular app by + /// name, creating an entry for one if it does not exist. + /// - Parameter app: The Firebase app to get the keychain service name for. + /// - Returns: The keychain service name for the given app. + static func keychainServiceName(for app: FirebaseApp) -> String { objc_sync_enter(Auth.self) defer { objc_sync_exit(Auth.self) } - return gKeychainServiceNameForAppName[appName] + let appName = app.name + if let serviceName = gKeychainServiceNameForAppName[appName] { + return serviceName + } else { + let serviceName = "firebase_auth_\(app.options.googleAppID)" + gKeychainServiceNameForAppName[appName] = serviceName + return serviceName + } } /// Deletes the keychain service name global data for the particular app by name. /// - Parameter appName: The name of the Firebase app to delete keychain service name for. - class func deleteKeychainServiceNameForAppName(_ appName: String) { + /// - Returns: The deleted keychain service name, if any. + static func deleteKeychainServiceNameForAppName(_ appName: String) -> String? { objc_sync_enter(Auth.self) + defer { objc_sync_exit(Auth.self) } + guard let serviceName = gKeychainServiceNameForAppName[appName] else { + return nil + } gKeychainServiceNameForAppName.removeValue(forKey: appName) - objc_sync_exit(Auth.self) + return serviceName } func signOutByForce(withUserID userID: String) throws { @@ -2364,7 +2370,7 @@ extension Auth: AuthInterop { // MARK: Private properties /// The stored user manager. - private var storedUserManager: AuthStoredUserManager! + private let storedUserManager: AuthStoredUserManager /// The Firebase app name. private let firebaseAppName: String @@ -2372,7 +2378,7 @@ extension Auth: AuthInterop { private let authDispatcher: AuthDispatcher /// The keychain service. - private var keychainServices: AuthKeychainServices! + private let keychainServices: AuthKeychainServices /// The user access (ID) token used last time for posting auth state changed notification. private var lastNotifiedUserToken: String? diff --git a/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift b/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift index 70ea440ebe5..649d274c294 100644 --- a/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift +++ b/FirebaseAuth/Sources/Swift/Auth/AuthComponent.swift @@ -77,8 +77,7 @@ class AuthComponent: NSObject, Library, ComponentLifecycleMaintainer { kAuthGlobalWorkQueue.async { // This doesn't stop any request already issued, see b/27704535 - if let keychainServiceName = Auth.keychainServiceName(forAppName: app.name) { - Auth.deleteKeychainServiceNameForAppName(app.name) + if let keychainServiceName = Auth.deleteKeychainServiceNameForAppName(app.name) { let keychain = AuthKeychainServices(service: keychainServiceName) let userKey = "\(app.name)_firebase_user" try? keychain.removeData(forKey: userKey) From d84d5ef671d30428215869fe6ab003894d5a7f25 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Mon, 18 Nov 2024 23:25:35 +0200 Subject: [PATCH 51/98] Update `FirebaseRemoteConfig` references (#14138) Signed-off-by: Emmanuel Ferdman --- FirebaseRemoteConfig/Tests/Swift/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FirebaseRemoteConfig/Tests/Swift/README.md b/FirebaseRemoteConfig/Tests/Swift/README.md index bb37d77d1e2..04e8d835164 100644 --- a/FirebaseRemoteConfig/Tests/Swift/README.md +++ b/FirebaseRemoteConfig/Tests/Swift/README.md @@ -6,7 +6,7 @@ Currently the Remote Config tests run in two configurations: ## Remote Config Console API -[`RemoteConfigConsole.swift`](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfigSwift/Tests/SwiftAPI/RemoteConfigConsole.swift) +[`RemoteConfigConsole.swift`](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/RemoteConfigConsole.swift) provides a simple API for interacting with an app's Remote Config on the Firebase console. @@ -18,7 +18,7 @@ then download a private key by clicking the blue button that says "Generate new Rename it `ServiceAccount.json`. 3. Within the `firebase-ios-sdk`, run: ```bash -./scripts/generate_access_token.sh local_dev PATH/TO/ServiceAccount.json FirebaseRemoteConfigSwift/Tests/AccessToken.json +./scripts/generate_access_token.sh local_dev PATH/TO/ServiceAccount.json FirebaseRemoteConfig/Tests/Swift/AccessToken.json ``` 4. Generate the `FirebaseRemoteConfig` project: ```bash @@ -55,6 +55,6 @@ Firebase project's service account key is stored. This is set in the script. #### Remote Config API Tests -There is a [section](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfigSwift/Tests/SwiftAPI/APITests.swift#L210) -of tests in [`APITests.swift`](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfigSwift/Tests/SwiftAPI/APITests.swift) +There is a [section](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift#L210) +of tests in [`APITests.swift`](https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift) showcasing the `RemoteConfigConsole` in action. From e8c71d1f7f3363b488f9f2045845afbb82fd016a Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:03:39 -0500 Subject: [PATCH 52/98] [Infra] Migrate away from macos-12 in performance.yml (#14131) Co-authored-by: Andrew Heard --- .github/workflows/performance.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index af24594c944..5a4c08e98a7 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -28,7 +28,7 @@ jobs: performance: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - runs-on: macos-12 + runs-on: macos-14 strategy: matrix: target: [iOS, tvOS] @@ -43,7 +43,6 @@ jobs: run: scripts/setup_bundler.sh - name: Install xcpretty run: gem install xcpretty - #TODO: Xcode 15 tests are blocked by #11903 - name: BuildAndTest # can be replaced with pod lib lint with CocoaPods 1.10 run: scripts/third_party/travis/retry.sh scripts/build.sh Performance ${{ matrix.target }} ${{ matrix.test }} From d2ff93c7c96b1dce761f067da4097815ce50531f Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:49:08 -0500 Subject: [PATCH 53/98] [Auth] Remove httpMethod from AuthRequestConfiguration (#14143) --- .../Sources/Swift/Backend/AuthBackend.swift | 23 +++++---------- .../Swift/Backend/AuthBackendRPCIssuer.swift | 9 ++++-- .../Swift/Backend/AuthRPCRequest.swift | 10 ++----- .../Backend/AuthRequestConfiguration.swift | 4 --- .../Backend/IdentityToolkitRequest.swift | 2 -- .../Backend/RPC/CreateAuthURIRequest.swift | 2 +- .../Backend/RPC/DeleteAccountRequest.swift | 2 +- .../Backend/RPC/EmailLinkSignInRequest.swift | 2 +- .../Backend/RPC/GetAccountInfoRequest.swift | 2 +- .../RPC/GetOOBConfirmationCodeRequest.swift | 2 +- .../Backend/RPC/GetProjectConfigRequest.swift | 9 ++---- .../RPC/GetRecaptchaConfigRequest.swift | 7 ++--- .../Enroll/FinalizeMFAEnrollmentRequest.swift | 2 +- .../Enroll/StartMFAEnrollmentRequest.swift | 2 +- .../SignIn/FinalizeMFASignInRequest.swift | 2 +- .../SignIn/StartMFASignInRequest.swift | 2 +- .../Unenroll/WithdrawMFARequest.swift | 2 +- .../Backend/RPC/ResetPasswordRequest.swift | 2 +- .../Backend/RPC/RevokeTokenRequest.swift | 2 +- .../Backend/RPC/SecureTokenRequest.swift | 4 +-- .../RPC/SendVerificationTokenRequest.swift | 2 +- .../Backend/RPC/SetAccountInfoRequest.swift | 2 +- .../RPC/SignInWithGameCenterRequest.swift | 2 +- .../Backend/RPC/SignUpNewUserRequest.swift | 2 +- .../Backend/RPC/VerifyAssertionRequest.swift | 2 +- .../RPC/VerifyCustomTokenRequest.swift | 2 +- .../Backend/RPC/VerifyPasswordRequest.swift | 2 +- .../RPC/VerifyPhoneNumberRequest.swift | 2 +- .../Swift/Backend/VerifyClientRequest.swift | 2 +- .../Tests/Unit/AuthBackendTests.swift | 28 +++++++++---------- .../Unit/Fakes/FakeBackendRPCIssuer.swift | 10 +++++-- .../Tests/Unit/GetRecaptchaConfigTests.swift | 2 +- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 2 +- 33 files changed, 64 insertions(+), 88 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 474f665147f..3c54b2792fd 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -60,7 +60,8 @@ final class AuthBackend: AuthBackendProtocol { } } - static func request(withURL url: URL, + static func request(for url: URL, + httpMethod: String, contentType: String, requestConfiguration: AuthRequestConfiguration) async -> URLRequest { // Kick off tasks for the async header values. @@ -76,7 +77,7 @@ final class AuthBackend: AuthBackendProtocol { request.setValue(clientVersion, forHTTPHeaderField: "X-Client-Version") request.setValue(Bundle.main.bundleIdentifier, forHTTPHeaderField: "X-Ios-Bundle-Identifier") request.setValue(requestConfiguration.appID, forHTTPHeaderField: "X-Firebase-GMPID") - request.httpMethod = requestConfiguration.httpMethod + request.httpMethod = httpMethod let preferredLocalizations = Bundle.main.preferredLocalizations if preferredLocalizations.count > 0 { request.setValue(preferredLocalizations.first, forHTTPHeaderField: "Accept-Language") @@ -163,21 +164,11 @@ final class AuthBackend: AuthBackendProtocol { /// - Returns: The response. fileprivate func callInternal(with request: T) async throws -> T.Response { var bodyData: Data? - if request.containsPostBody { - var postBody: [String: AnyHashable] - do { - // TODO: Can unencodedHTTPRequestBody ever throw? - // They don't today, but there are a few fatalErrors that might better be implemented as - // thrown errors.. Although perhaps the case of 'containsPostBody' returning false could - // perhaps be modeled differently so that the failing unencodedHTTPRequestBody could only - // be called when a body exists... - postBody = try request.unencodedHTTPRequestBody() - } catch { - throw AuthErrorUtils.RPCRequestEncodingError(underlyingError: error) - } - var JSONWritingOptions: JSONSerialization.WritingOptions = .init(rawValue: 0) + if let postBody = request.unencodedHTTPRequestBody { #if DEBUG - JSONWritingOptions = JSONSerialization.WritingOptions.prettyPrinted + let JSONWritingOptions = JSONSerialization.WritingOptions.prettyPrinted + #else + let JSONWritingOptions = JSONSerialization.WritingOptions(rawValue: 0) #endif guard JSONSerialization.isValidJSONObject(postBody) else { diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift index 6d2c540ff37..bcf4f6dcab8 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackendRPCIssuer.swift @@ -52,9 +52,12 @@ final class AuthBackendRPCIssuer: AuthBackendRPCIssuerProtocol { body: Data?, contentType: String) async -> (Data?, Error?) { let requestConfiguration = request.requestConfiguration() - let request = await AuthBackend.request(withURL: request.requestURL(), - contentType: contentType, - requestConfiguration: requestConfiguration) + let request = await AuthBackend.request( + for: request.requestURL(), + httpMethod: body == nil ? "GET" : "POST", + contentType: contentType, + requestConfiguration: requestConfiguration + ) let fetcher = fetcherService.fetcher(with: request) if let _ = requestConfiguration.emulatorHostAndPort { fetcher.allowLocalhostRequest = true diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthRPCRequest.swift b/FirebaseAuth/Sources/Swift/Backend/AuthRPCRequest.swift index 34f40d82f88..eeacfbea897 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthRPCRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthRPCRequest.swift @@ -22,14 +22,11 @@ protocol AuthRPCRequest { /// Gets the request's full URL. func requestURL() -> URL - /// Returns whether the request contains a post body or not. Requests without a post body are - /// GET requests. A default implementation returns `true`. - var containsPostBody: Bool { get } - /// Creates unencoded HTTP body representing the request. - /// - Throws: Any error which occurred constructing the request. /// - Returns: The HTTP body data representing the request before any encoding. - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] + /// - Note: Requests with a post body are POST requests. Requests without a + /// post body are GET requests. + var unencodedHTTPRequestBody: [String: AnyHashable]? { get } /// The request configuration. func requestConfiguration() -> AuthRequestConfiguration @@ -41,7 +38,6 @@ protocol AuthRPCRequest { // in Obj-C. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) extension AuthRPCRequest { - var containsPostBody: Bool { return true } func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String) { fatalError("Internal FirebaseAuth Error: unimplemented injectRecaptchaFields") } diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift b/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift index 47aff1be47e..510e9287ca0 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift @@ -38,9 +38,6 @@ class AuthRequestConfiguration { /// The appCheck is used to generate a token. var appCheck: AppCheckInterop? - /// The HTTP method used in the request. - var httpMethod: String - /// Additional framework marker that will be added as part of the header of every request. var additionalFrameworkMarker: String? @@ -57,6 +54,5 @@ class AuthRequestConfiguration { self.auth = auth self.heartbeatLogger = heartbeatLogger self.appCheck = appCheck - httpMethod = "POST" } } diff --git a/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift b/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift index 3a5d5a3b18a..08f9f9f30d6 100644 --- a/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/IdentityToolkitRequest.swift @@ -70,8 +70,6 @@ class IdentityToolkitRequest { tenantID = requestConfiguration.auth?.tenantID } - var containsPostBody: Bool { return true } - func queryParams() -> String { return "" } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIRequest.swift index 419419f4862..987b7d28fe6 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/CreateAuthURIRequest.swift @@ -78,7 +78,7 @@ class CreateAuthURIRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kCreateAuthURIEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [ kIdentifierKey: identifier, kContinueURIKey: continueURI, diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountRequest.swift index 81856a0c027..543d5af3b8f 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/DeleteAccountRequest.swift @@ -41,7 +41,7 @@ class DeleteAccountRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kDeleteAccountEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { [ kIDTokenKey: accessToken, kLocalIDKey: localID, diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInRequest.swift index b57c2170450..72a23517985 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/EmailLinkSignInRequest.swift @@ -51,7 +51,7 @@ class EmailLinkSignInRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kEmailLinkSigninEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [ kEmailKey: email, kOOBCodeKey: oobCode, diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoRequest.swift index 3e30fae5242..5dba854b172 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetAccountInfoRequest.swift @@ -39,7 +39,7 @@ class GetAccountInfoRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kGetAccountInfoEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { return [kIDTokenKey: accessToken] } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift index c1de49fd071..e2437a569bd 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetOOBConfirmationCodeRequest.swift @@ -228,7 +228,7 @@ class GetOOBConfirmationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [ kRequestTypeKey: requestType.value, ] diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigRequest.swift index 1b8f714b60e..1a1b011ff01 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetProjectConfigRequest.swift @@ -15,7 +15,6 @@ import Foundation /// The "getProjectConfig" endpoint. - private let kGetProjectConfigEndPoint = "getProjectConfig" @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @@ -23,14 +22,10 @@ class GetProjectConfigRequest: IdentityToolkitRequest, AuthRPCRequest { typealias Response = GetProjectConfigResponse init(requestConfiguration: AuthRequestConfiguration) { - requestConfiguration.httpMethod = "GET" super.init(endpoint: kGetProjectConfigEndPoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { - // TODO: Probably nicer to throw, but what should we throw? - fatalError() + var unencodedHTTPRequestBody: [String: AnyHashable]? { + nil } - - override var containsPostBody: Bool { return false } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigRequest.swift index fc8e287a52f..075d8273a15 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/GetRecaptchaConfigRequest.swift @@ -48,7 +48,6 @@ class GetRecaptchaConfigRequest: IdentityToolkitRequest, AuthRPCRequest { typealias Response = GetRecaptchaConfigResponse required init(requestConfiguration: AuthRequestConfiguration) { - requestConfiguration.httpMethod = "GET" super.init( endpoint: kGetRecaptchaConfigEndpoint, requestConfiguration: requestConfiguration, @@ -56,12 +55,10 @@ class GetRecaptchaConfigRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { - return [:] + var unencodedHTTPRequestBody: [String: AnyHashable]? { + nil } - override var containsPostBody: Bool { return false } - override func queryParams() -> String { var queryParams = "&\(kClientTypeKey)=\(clientType)&\(kVersionKey)=\(kRecaptchaVersion)" if let tenantID { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentRequest.swift index 89374c9de4f..0c1154d5a68 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/FinalizeMFAEnrollmentRequest.swift @@ -71,7 +71,7 @@ class FinalizeMFAEnrollmentRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [:] if let idToken = idToken { body["idToken"] = idToken diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift index 3896ec14b3d..467733768fc 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift @@ -64,7 +64,7 @@ class StartMFAEnrollmentRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [:] if let idToken = idToken { body["idToken"] = idToken diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInRequest.swift index 399e426d456..7e8b67eca96 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/FinalizeMFASignInRequest.swift @@ -36,7 +36,7 @@ class FinalizeMFASignInRequest: IdentityToolkitRequest, AuthRPCRequest { useIdentityPlatform: true) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [:] if let mfaPendingCredential = mfaPendingCredential { body["mfaPendingCredential"] = mfaPendingCredential diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift index 1098c2ef4ea..82e1a1721bd 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift @@ -41,7 +41,7 @@ class StartMFASignInRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [:] if let MFAPendingCredential = MFAPendingCredential { body["mfaPendingCredential"] = MFAPendingCredential diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFARequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFARequest.swift index 19d9a04faed..f2324db3ca2 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFARequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Unenroll/WithdrawMFARequest.swift @@ -36,7 +36,7 @@ class WithdrawMFARequest: IdentityToolkitRequest, AuthRPCRequest { useIdentityPlatform: true) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] if let idToken = idToken { postBody["idToken"] = idToken diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordRequest.swift index aa39c927b83..c0b2629683d 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/ResetPasswordRequest.swift @@ -48,7 +48,7 @@ class ResetPasswordRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kResetPasswordEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] postBody[kOOBCodeKey] = oobCode diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenRequest.swift index c3afae3b573..94e6deeeabb 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/RevokeTokenRequest.swift @@ -71,7 +71,7 @@ class RevokeTokenRequest: IdentityToolkitRequest, AuthRPCRequest { useIdentityPlatform: true) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { let body: [String: AnyHashable] = [ kProviderIDKey: providerID, kTokenTypeKey: "\(tokenType.rawValue)", diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift index d11275dcf29..175b1889b96 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SecureTokenRequest.swift @@ -134,9 +134,7 @@ class SecureTokenRequest: AuthRPCRequest { return URL(string: urlString)! } - var containsPostBody: Bool { return true } - - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [ kGrantTypeKey: grantType.value, ] diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift index af090fdd3b3..a87ff833c10 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift @@ -60,7 +60,7 @@ class SendVerificationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] postBody[kPhoneNumberKey] = phoneNumber switch codeIdentity { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoRequest.swift index 82842ace520..5e310d4a656 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SetAccountInfoRequest.swift @@ -136,7 +136,7 @@ class SetAccountInfoRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kSetAccountInfoEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] if let accessToken { postBody[kIDTokenKey] = accessToken diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift index adab76dcd34..7d722326f71 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift @@ -76,7 +76,7 @@ class SignInWithGameCenterRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [ "playerId": playerID, "publicKeyUrl": publicKeyURL.absoluteString, diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserRequest.swift index 12308573334..68cfe6b5e38 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignUpNewUserRequest.swift @@ -89,7 +89,7 @@ class SignUpNewUserRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kSignupNewUserEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] if let email { postBody[kEmailKey] = email diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionRequest.swift index 9e8d8b6b86d..30c924ff403 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyAssertionRequest.swift @@ -135,7 +135,7 @@ class VerifyAssertionRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kVerifyAssertionEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var components = URLComponents() var queryItems: [URLQueryItem] = [URLQueryItem(name: kProviderIDKey, value: providerID)] if let providerIDToken = providerIDToken { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenRequest.swift index af1518ee653..b8a97278908 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyCustomTokenRequest.swift @@ -40,7 +40,7 @@ class VerifyCustomTokenRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kVerifyCustomTokenEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [ kTokenKey: token, ] diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordRequest.swift index 2c9fc19d17c..4c1096d5fbe 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPasswordRequest.swift @@ -79,7 +79,7 @@ class VerifyPasswordRequest: IdentityToolkitRequest, AuthRPCRequest { super.init(endpoint: kVerifyPasswordEndpoint, requestConfiguration: requestConfiguration) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var body: [String: AnyHashable] = [ kEmailKey: email, kPasswordKey: password, diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberRequest.swift index 791c6fc9e01..07ddf167527 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/VerifyPhoneNumberRequest.swift @@ -133,7 +133,7 @@ class VerifyPhoneNumberRequest: IdentityToolkitRequest, AuthRPCRequest { ) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody: [String: AnyHashable] = [:] if let verificationID { postBody[kVerificationIDKey] = verificationID diff --git a/FirebaseAuth/Sources/Swift/Backend/VerifyClientRequest.swift b/FirebaseAuth/Sources/Swift/Backend/VerifyClientRequest.swift index f62f9def230..5821fc55c7e 100644 --- a/FirebaseAuth/Sources/Swift/Backend/VerifyClientRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/VerifyClientRequest.swift @@ -27,7 +27,7 @@ class VerifyClientRequest: IdentityToolkitRequest, AuthRPCRequest { /// The key for the isSandbox request parameter. private static let isSandboxKey = "isSandbox" - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { + var unencodedHTTPRequestBody: [String: AnyHashable]? { var postBody = [String: AnyHashable]() if let appToken = appToken { postBody[Self.appTokenKey] = appToken diff --git a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift index 5feaf239e3b..6056bbae362 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift @@ -50,13 +50,7 @@ class AuthBackendTests: RPCBaseTests { let underlyingError = try XCTUnwrap(rpcError.userInfo[NSUnderlyingErrorKey] as? NSError) XCTAssertEqual(underlyingError.domain, AuthErrorUtils.internalErrorDomain) - XCTAssertEqual(underlyingError.code, AuthInternalErrorCode.RPCRequestEncodingError.rawValue) - - let underlyingUnderlying = try XCTUnwrap(underlyingError - .userInfo[NSUnderlyingErrorKey] as? NSError) - XCTAssertEqual(underlyingUnderlying.domain, kFakeErrorDomain) - XCTAssertEqual(underlyingUnderlying.code, kFakeErrorCode) - + XCTAssertEqual(underlyingError.code, AuthInternalErrorCode.JSONSerializationError.rawValue) XCTAssertNil(underlyingError.userInfo[AuthErrorUtils.userInfoDeserializedResponseKey]) XCTAssertNil(underlyingError.userInfo[AuthErrorUtils.userInfoDataKey]) } @@ -670,11 +664,17 @@ class AuthBackendTests: RPCBaseTests { return try! XCTUnwrap(URL(string: kFakeRequestURL)) } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { - if let encodingError { - throw encodingError + var unencodedHTTPRequestBody: [String: AnyHashable]? { + if encodingError == nil { + return requestBody } - return requestBody + // Else, return an unencodable request body that will cause an error to be thrown. + struct UnencodableObject: Hashable { + static func == (lhs: UnencodableObject, rhs: UnencodableObject) -> Bool { + true + } + } + return ["foo": UnencodableObject()] } static func makeRequestConfiguration() -> AuthRequestConfiguration { @@ -684,8 +684,6 @@ class AuthBackendTests: RPCBaseTests { ) } - var containsPostBody: Bool { return true } - private let configuration: AuthRequestConfiguration let encodingError: NSError? @@ -724,8 +722,8 @@ class AuthBackendTests: RPCBaseTests { return fakeRequest.requestURL() } - func unencodedHTTPRequestBody() throws -> [String: AnyHashable] { - return try fakeRequest.unencodedHTTPRequestBody() + var unencodedHTTPRequestBody: [String: AnyHashable]? { + fakeRequest.unencodedHTTPRequestBody } func requestConfiguration() -> FirebaseAuth.AuthRequestConfiguration { diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift index 3a40aac37d7..9131a19f98f 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift @@ -148,9 +148,13 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda // Use the real implementation so that the complete request can // be verified during testing. completeRequest = Task { - await AuthBackend.request(withURL: requestURL!, - contentType: contentType, - requestConfiguration: request.requestConfiguration()) + await AuthBackend + .request( + for: request.requestURL(), + httpMethod: requestData == nil ? "GET" : "POST", + contentType: contentType, + requestConfiguration: request.requestConfiguration() + ) } decodedRequest = try? JSONSerialization.jsonObject(with: body) as? [String: Any] } diff --git a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift index 75149c38d45..6638d6bfcc1 100644 --- a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift +++ b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift @@ -25,7 +25,7 @@ class GetRecaptchaConfigTests: RPCBaseTests { func testGetRecaptchaConfigRequest() async throws { let request = GetRecaptchaConfigRequest(requestConfiguration: makeRequestConfiguration()) // let _ = try await authBackend.call(with: request) - XCTAssertFalse(request.containsPostBody) + XCTAssertNil(request.unencodedHTTPRequestBody) // Confirm that the request has no decoded body as it is get request. XCTAssertNil(rpcIssuer.decodedRequest) diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 9a8f9026ea9..bb7a247fadf 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -91,7 +91,7 @@ class RPCBaseTests: XCTestCase { rpcIssuer.respondBlock = { XCTAssertEqual(self.rpcIssuer.requestURL?.absoluteString, expected) if checkPostBody { - XCTAssertFalse(request.containsPostBody) + XCTAssertNil(request.unencodedHTTPRequestBody) } else if let requestDictionary = self.rpcIssuer.decodedRequest as? [String: AnyHashable] { XCTAssertEqual(requestDictionary[key], value) } else { From 6b99ad1fa2f32e2e9fa08f7be623d04070823b35 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:44:24 -0500 Subject: [PATCH 54/98] [Auth] Mark AuthRequestConfiguration as final and reduce its mutability (#14147) --- FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift | 3 +-- .../Sources/Swift/Backend/AuthRequestConfiguration.swift | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 3c54b2792fd..f981701b98e 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -71,8 +71,7 @@ final class AuthBackend: AuthBackendProtocol { var request = URLRequest(url: url) request.setValue(contentType, forHTTPHeaderField: "Content-Type") - let additionalFrameworkMarker = requestConfiguration - .additionalFrameworkMarker ?? "FirebaseCore-iOS" + let additionalFrameworkMarker = requestConfiguration.additionalFrameworkMarker let clientVersion = "iOS/FirebaseSDK/\(FirebaseVersion())/\(additionalFrameworkMarker)" request.setValue(clientVersion, forHTTPHeaderField: "X-Client-Version") request.setValue(Bundle.main.bundleIdentifier, forHTTPHeaderField: "X-Ios-Bundle-Identifier") diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift b/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift index 510e9287ca0..91f99c266f8 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthRequestConfiguration.swift @@ -19,7 +19,7 @@ import FirebaseCoreExtension /// Defines configurations to be added to a request to Firebase Auth's backend. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -class AuthRequestConfiguration { +final class AuthRequestConfiguration { /// The Firebase Auth API key used in the request. let apiKey: String @@ -33,13 +33,13 @@ class AuthRequestConfiguration { weak var auth: Auth? /// The heartbeat logger used to add heartbeats to the corresponding request's header. - var heartbeatLogger: FIRHeartbeatLoggerProtocol? + let heartbeatLogger: FIRHeartbeatLoggerProtocol? /// The appCheck is used to generate a token. var appCheck: AppCheckInterop? /// Additional framework marker that will be added as part of the header of every request. - var additionalFrameworkMarker: String? + let additionalFrameworkMarker: String = "FirebaseCore-iOS" /// If set, the local emulator host and port to point to instead of the remote backend. var emulatorHostAndPort: String? From 380a8618823f1fa7440cb30059025710ae1d7e5e Mon Sep 17 00:00:00 2001 From: Liubin Jiang <56564857+Xiaoshouzi-gh@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:15:03 -0800 Subject: [PATCH 55/98] [Auth] Add MFA view controller and support MFA on Swift sample app (#14111) Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- .../project.pbxproj | 8 +- .../CustomViews/MFALoginView.swift | 189 ++++++++++++++++++ .../Models/OtherAuthMethods.swift | 17 ++ .../Utility/LoginDelegate.swift | 3 +- .../ViewControllers/AuthViewController.swift | 90 +++++---- .../ViewControllers/LoginController.swift | 16 +- .../CustomAuthViewController.swift | 2 +- .../OtherAuthViewController.swift | 4 +- .../PasswordlessViewController.swift | 2 +- .../PhoneAuthViewController.swift | 2 +- 10 files changed, 283 insertions(+), 50 deletions(-) create mode 100644 FirebaseAuth/Tests/SampleSwift/AuthenticationExample/CustomViews/MFALoginView.swift diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj index 2160a626445..feb55512ba4 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ EA527CAC24A0EE9600ADB9A2 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */; }; EAB3A1792494433500385291 /* DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB3A1782494433500385291 /* DataSourceProvider.swift */; }; EAB3A17C2494628200385291 /* UserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB3A17B2494628200385291 /* UserViewController.swift */; }; + EAD8BD402CE535C400E23E30 /* MFALoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8BD3F2CE535C400E23E30 /* MFALoginView.swift */; }; EAE08EB524CF5D09006FA3A5 /* AccountLinkingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE08EB424CF5D09006FA3A5 /* AccountLinkingViewController.swift */; }; EAE4CBC524855E3A00245E92 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4CBC424855E3A00245E92 /* AppDelegate.swift */; }; EAE4CBC724855E3A00245E92 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4CBC624855E3A00245E92 /* SceneDelegate.swift */; }; @@ -128,6 +129,7 @@ EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; EAB3A1782494433500385291 /* DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceProvider.swift; sourceTree = ""; }; EAB3A17B2494628200385291 /* UserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewController.swift; sourceTree = ""; }; + EAD8BD3F2CE535C400E23E30 /* MFALoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFALoginView.swift; sourceTree = ""; }; EAE08EB424CF5D09006FA3A5 /* AccountLinkingViewController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AccountLinkingViewController.swift; sourceTree = ""; }; EAE4CBC124855E3A00245E92 /* AuthenticationExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AuthenticationExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; EAE4CBC424855E3A00245E92 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -244,6 +246,7 @@ EA20B47724973BB100B5E581 /* CustomViews */ = { isa = PBXGroup; children = ( + EAD8BD3F2CE535C400E23E30 /* MFALoginView.swift */, EA20B46B2495A9F900B5E581 /* SignedOutView.swift */, EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */, ); @@ -561,6 +564,7 @@ EA20B510249FDB4400B5E581 /* OtherAuthMethods.swift in Sources */, EA12697F29E33A5D00D79E66 /* CryptoUtils.swift in Sources */, EAEBCE11248A9AA000FCEA92 /* Section.swift in Sources */, + EAD8BD402CE535C400E23E30 /* MFALoginView.swift in Sources */, DEC2E5DF2A9583CA0090260A /* AppManager.swift in Sources */, DEC2E5DD2A95331E0090260A /* SettingsViewController.swift in Sources */, EA20B503249C6C3D00B5E581 /* CustomAuthViewController.swift in Sources */, @@ -789,7 +793,7 @@ CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = AuthenticationExample/SwiftApplication.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -812,7 +816,7 @@ CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = AuthenticationExample/SwiftApplication.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/CustomViews/MFALoginView.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/CustomViews/MFALoginView.swift new file mode 100644 index 00000000000..2f9d64f82c3 --- /dev/null +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/CustomViews/MFALoginView.swift @@ -0,0 +1,189 @@ +// Copyright 2024 Google LLC +// +// 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 FirebaseAuth +import SwiftUI + +struct MFALoginView: View { + @Environment(\.dismiss) private var dismiss + + @State private var factorSelection: MultiFactorInfo? + // This is only needed for phone MFA. + @State private var verificationId: String? + // This is needed for both phone and TOTP MFA. + @State private var verificationCode: String = "" + + private let resolver: MultiFactorResolver + private weak var delegate: (any LoginDelegate)? + + init(resolver: MultiFactorResolver, delegate: (any LoginDelegate)?) { + self.resolver = resolver + self.delegate = delegate + } + + var body: some View { + Text("Choose a second factor to continue.") + .padding(.top) + List(resolver.hints, id: \.self, selection: $factorSelection) { + Text($0.displayName ?? "No display name provided.") + } + .frame(height: 300) + .clipShape(RoundedRectangle(cornerRadius: 15)) + .padding() + + if let factorSelection { + // TODO(ncooke3): This logic handles both phone and TOTP MFA states. Investigate how to make + // more clear with better APIs. + if factorSelection.factorID == PhoneMultiFactorID, verificationId == nil { + MFAViewButton( + text: "Send Verification Code", + accentColor: .white, + backgroundColor: .orange + ) { + Task { await startMfALogin() } + } + .padding() + } else { + TextField("Enter verification code.", text: $verificationCode) + .textFieldStyle(SymbolTextField(symbolName: "lock.circle.fill")) + .padding() + MFAViewButton( + text: "Sign in", + accentColor: .white, + backgroundColor: .orange + ) { + Task { await finishMfALogin() } + } + .padding() + } + } + Spacer() + } +} + +extension MFALoginView { + private func startMfALogin() async { + guard let factorSelection else { return } + switch factorSelection.factorID { + case PhoneMultiFactorID: + await startPhoneMultiFactorSignIn(hint: factorSelection as? PhoneMultiFactorInfo) + case TOTPMultiFactorID: break // TODO(ncooke3): Indicate to user to get verification code. + default: return + } + } + + private func startPhoneMultiFactorSignIn(hint: PhoneMultiFactorInfo?) async { + guard let hint else { return } + do { + verificationId = try await PhoneAuthProvider.provider().verifyPhoneNumber( + with: hint, + uiDelegate: nil, + multiFactorSession: resolver.session + ) + } catch { + print(error) + } + } + + private func finishMfALogin() async { + guard let factorSelection else { return } + switch factorSelection.factorID { + case PhoneMultiFactorID: + await finishPhoneMultiFactorSignIn() + case TOTPMultiFactorID: + await finishTOTPMultiFactorSignIn(hint: factorSelection) + default: return + } + } + + private func finishPhoneMultiFactorSignIn() async { + guard let verificationId else { return } + let credential = PhoneAuthProvider.provider().credential( + withVerificationID: verificationId, + verificationCode: verificationCode + ) + let assertion = PhoneMultiFactorGenerator.assertion(with: credential) + do { + _ = try await resolver.resolveSignIn(with: assertion) + // MFA login was successful. + await MainActor.run { + dismiss() + delegate?.loginDidOccur(resolver: nil) + } + } catch { + print(error) + } + } + + private func finishTOTPMultiFactorSignIn(hint: MultiFactorInfo) async { + // TODO(ncooke3): Disable button if verification code textfield contents is empty. + guard verificationCode.count > 0 else { return } + let assertion = TOTPMultiFactorGenerator.assertionForSignIn( + withEnrollmentID: hint.uid, + oneTimePassword: verificationCode + ) + do { + _ = try await resolver.resolveSignIn(with: assertion) + // MFA login was successful. + await MainActor.run { + dismiss() + delegate?.loginDidOccur(resolver: nil) + } + } catch { + // Wrong or expired OTP. Re-prompt the user. + // TODO(ncooke3): Show error to user. + print(error) + } + } +} + +private struct MFAViewButton: View { + let text: String + let accentColor: Color + let backgroundColor: Color + let action: () -> Void + + var body: some View { + Button(action: action) { + HStack { + Spacer() + Text(text) + .bold() + .accentColor(accentColor) + Spacer() + } + .padding() + .background(backgroundColor) + .cornerRadius(14) + } + } +} + +private struct SymbolTextField: TextFieldStyle { + let symbolName: String + + func _body(configuration: TextField) -> some View { + HStack { + Image(systemName: symbolName) + .foregroundColor(.orange) + .imageScale(.large) + .padding(.leading) + configuration + .padding([.vertical, .trailing]) + } + .background(Color(uiColor: .secondarySystemBackground)) + .cornerRadius(14) + .textInputAutocapitalization(.never) + } +} diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Models/OtherAuthMethods.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Models/OtherAuthMethods.swift index 5566e79bc8d..ed60efeecad 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Models/OtherAuthMethods.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Models/OtherAuthMethods.swift @@ -19,6 +19,7 @@ enum OtherAuthMethod: String { case Passwordless = "Email Link/Passwordless" case PhoneNumber = "Phone Auth" case Custom = "a Custom Auth System" + case MfaLogin = "Multifactor Authentication" var navigationTitle: String { "Sign in using \(rawValue)" } @@ -30,6 +31,8 @@ enum OtherAuthMethod: String { return "Enter Phone Number" case .Custom: return "Enter Custom Auth Token" + case .MfaLogin: + return "Choose a Second Factor to Continue" } } @@ -41,6 +44,8 @@ enum OtherAuthMethod: String { return "phone.circle" case .Custom: return "lock.shield" + case .MfaLogin: + return "phone.circle" } } @@ -48,6 +53,8 @@ enum OtherAuthMethod: String { switch self { case .PhoneNumber: return "Example input for +1 (123)456-7890 would be 11234567890" + case .MfaLogin: + return "Enter the index of the selected factor to continue" default: return nil } @@ -61,6 +68,8 @@ enum OtherAuthMethod: String { return "Send Verification Code" case .Custom: return "Login" + case .MfaLogin: + return "Send Verification Code" } } @@ -72,9 +81,17 @@ enum OtherAuthMethod: String { return phoneNumberInfoText case .Custom: return customAuthInfoText + case .MfaLogin: + return mfaLoginInfoText } } + private var mfaLoginInfoText: String { + """ + MFA placeholder + """ + } + private var passwordlessInfoText: String { """ Authenticate users with only their email, \ diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/LoginDelegate.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/LoginDelegate.swift index d1420d8923a..b76daa2a6a3 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/LoginDelegate.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/LoginDelegate.swift @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseAuth import Foundation /// Delegate for signaling that a successful login with Firebase Auth has occurred protocol LoginDelegate: NSObject { - func loginDidOccur() + func loginDidOccur(resolver: MultiFactorResolver?) } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift index e9567a69e9d..7f8b77856f0 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift @@ -27,6 +27,8 @@ import GameKit import GoogleSignIn import UIKit +import SwiftUI + // For Sign in with Apple import AuthenticationServices import CryptoKit @@ -202,54 +204,50 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { // [END_EXCLUDE] let config = GIDConfiguration(clientID: clientID) GIDSignIn.sharedInstance.configuration = config + Task { + do { + let result = try await GIDSignIn.sharedInstance.signIn(withPresenting: self) + let user = result.user + guard let idToken = user.idToken?.tokenString + else { + // [START_EXCLUDE] + let error = NSError( + domain: "GIDSignInError", + code: -1, + userInfo: [ + NSLocalizedDescriptionKey: "Unexpected sign in result: required authentication data is missing.", + ] + ) + return displayError(error) + // [END_EXCLUDE] + } + let credential = GoogleAuthProvider.credential(withIDToken: idToken, + accessToken: user.accessToken.tokenString) + try await signIn(with: credential) - // Start the sign in flow! - GIDSignIn.sharedInstance.signIn(withPresenting: self) { [unowned self] result, error in - guard error == nil else { - // [START_EXCLUDE] - return displayError(error) - // [END_EXCLUDE] - } - - guard let user = result?.user, - let idToken = user.idToken?.tokenString - else { - // [START_EXCLUDE] - let error = NSError( - domain: "GIDSignInError", - code: -1, - userInfo: [ - NSLocalizedDescriptionKey: "Unexpected sign in result: required authentication data is missing.", - ] - ) + } catch { return displayError(error) - // [END_EXCLUDE] } - let credential = GoogleAuthProvider.credential(withIDToken: idToken, - accessToken: user.accessToken.tokenString) - - // [START_EXCLUDE] - signIn(with: credential) // [END_EXCLUDE] } // [END headless_google_auth] } - func signIn(with credential: AuthCredential) { - // [START signin_google_credential] - AppManager.shared.auth().signIn(with: credential) { result, error in - // [START_EXCLUDE silent] - guard error == nil else { return self.displayError(error) } - // [END_EXCLUDE] - - // At this point, our user is signed in - // [START_EXCLUDE silent] - // so we advance to the User View Controller - self.transitionToUserViewController() - // [END_EXCLUDE] + func signIn(with credential: AuthCredential) async throws { + do { + _ = try await AppManager.shared.auth().signIn(with: credential) + transitionToUserViewController() + } catch { + let authError = error as NSError + if authError.code == AuthErrorCode.secondFactorRequired.rawValue { + let resolver = authError + .userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver + performMfaLoginFlow(resolver: resolver) + } else { + return displayError(error) + } } - // [END signin_google_credential] } // For Sign in with Apple @@ -358,6 +356,14 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { navigationController?.present(navPhoneAuthController, animated: true) } + private func performMfaLoginFlow(resolver: MultiFactorResolver) { + let mfaLoginController = UIHostingController(rootView: MFALoginView( + resolver: resolver, + delegate: self + )) + present(mfaLoginController, animated: true) + } + private func performAnonymousLoginFlow() { AppManager.shared.auth().signInAnonymously { result, error in guard error == nil else { return self.displayError(error) } @@ -1064,8 +1070,12 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { // MARK: - LoginDelegate extension AuthViewController: LoginDelegate { - public func loginDidOccur() { - transitionToUserViewController() + public func loginDidOccur(resolver: MultiFactorResolver?) { + if let resolver { + performMfaLoginFlow(resolver: resolver) + } else { + transitionToUserViewController() + } } } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift index 1ca3c9df197..36befea2bfd 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift @@ -64,15 +64,25 @@ class LoginController: UIViewController { private func login(with email: String, password: String) { AppManager.shared.auth().signIn(withEmail: email, password: password) { result, error in - guard error == nil else { return self.displayError(error) } - self.delegate?.loginDidOccur() + if let error { + let authError = error as NSError + if authError.code == AuthErrorCode.secondFactorRequired.rawValue { + let resolver = authError + .userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver + self.delegate?.loginDidOccur(resolver: resolver) + } else { + self.displayError(error) + } + } else { + self.delegate?.loginDidOccur(resolver: nil) + } } } private func createUser(email: String, password: String) { AppManager.shared.auth().createUser(withEmail: email, password: password) { authResult, error in guard error == nil else { return self.displayError(error) } - self.delegate?.loginDidOccur() + self.delegate?.loginDidOccur(resolver: nil) } } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/CustomAuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/CustomAuthViewController.swift index da4248447de..0787a32447d 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/CustomAuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/CustomAuthViewController.swift @@ -32,7 +32,7 @@ class CustomAuthViewController: OtherAuthViewController { AppManager.shared.auth().signIn(withCustomToken: token) { result, error in guard error == nil else { return self.displayError(error) } self.navigationController?.dismiss(animated: true, completion: { - self.delegate?.loginDidOccur() + self.delegate?.loginDidOccur(resolver: nil) }) } } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/OtherAuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/OtherAuthViewController.swift index 846e1f39d2d..dd2f2a60eb0 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/OtherAuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/OtherAuthViewController.swift @@ -27,7 +27,7 @@ class OtherAuthViewController: UIViewController { return textField }() - private var textFieldInputLabel: UILabel? + var textFieldInputLabel: UILabel? private lazy var button: UIButton = { let button = UIButton() @@ -113,6 +113,8 @@ class OtherAuthViewController: UIViewController { let label = UILabel() label.font = .systemFont(ofSize: 12) label.textColor = .secondaryLabel + // unlimited line breaks + label.numberOfLines = 0 label.text = text label.alpha = UIDevice.current.orientation.isLandscape ? 0 : 1 label.translatesAutoresizingMaskIntoConstraints = false diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PasswordlessViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PasswordlessViewController.swift index d710f323a6a..58609b9d925 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PasswordlessViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PasswordlessViewController.swift @@ -67,7 +67,7 @@ class PasswordlessViewController: OtherAuthViewController { print("User verified with passwordless email.") self.navigationController?.dismiss(animated: true) { - self.delegate?.loginDidOccur() + self.delegate?.loginDidOccur(resolver: nil) } } else { print("User could not be verified by passwordless email") diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift index a4e19077aad..f1a29ded31d 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift @@ -47,7 +47,7 @@ class PhoneAuthViewController: OtherAuthViewController { AppManager.shared.auth().signIn(with: credential) { result, error in guard error == nil else { return self.displayError(error) } self.navigationController?.dismiss(animated: true, completion: { - self.delegate?.loginDidOccur() + self.delegate?.loginDidOccur(resolver: nil) }) } } From db77a779dc76d911c7c6dc0a81cb16352252bcac Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 20 Nov 2024 13:14:58 -0500 Subject: [PATCH 56/98] [Infra] Add check for unexpected test failures in build.sh (#14144) --- .../Tests/Unit/Timer/FPRCounterListTest.m | 4 ++++ scripts/build.sh | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/FirebasePerformance/Tests/Unit/Timer/FPRCounterListTest.m b/FirebasePerformance/Tests/Unit/Timer/FPRCounterListTest.m index d31cd61c6e1..00b2c78d38f 100644 --- a/FirebasePerformance/Tests/Unit/Timer/FPRCounterListTest.m +++ b/FirebasePerformance/Tests/Unit/Timer/FPRCounterListTest.m @@ -29,14 +29,18 @@ + (void)setUp { [super setUp]; FIRPerformance *performance = [FIRPerformance sharedInstance]; [performance setDataCollectionEnabled:YES]; +#ifdef UNSWIZZLE_AVAILABLE [[FPRClient sharedInstance] disableInstrumentation]; +#endif // UNSWIZZLE_AVAILABLE } + (void)tearDown { [super tearDown]; FIRPerformance *performance = [FIRPerformance sharedInstance]; [performance setDataCollectionEnabled:NO]; +#ifdef UNSWIZZLE_AVAILABLE [[FPRClient sharedInstance] disableInstrumentation]; +#endif // UNSWIZZLE_AVAILABLE } /** Validates counterlist object creation. */ diff --git a/scripts/build.sh b/scripts/build.sh index 67e576ac990..15019bd184c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -110,10 +110,12 @@ source scripts/check_secrets.sh function RunXcodebuild() { echo xcodebuild "$@" - xcbeautify_cmd=(xcbeautify --renderer github-actions) + xcbeautify_cmd=(xcbeautify --renderer github-actions --disable-logging) result=0 - xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" || result=$? + xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" \ + && CheckUnexpectedFailures xcodebuild.log \ + || result=$? if [[ $result == 65 ]]; then ExportLogs "$@" @@ -122,7 +124,9 @@ function RunXcodebuild() { sleep 5 result=0 - xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" || result=$? + xcodebuild "$@" | tee xcodebuild.log | "${xcbeautify_cmd[@]}" \ + && CheckUnexpectedFailures xcodebuild.log \ + || result=$? fi if [[ $result != 0 ]]; then @@ -138,6 +142,15 @@ function ExportLogs() { python "${scripts_dir}/xcresult_logs.py" "$@" } +function CheckUnexpectedFailures() { + local log_file=$1 + + if grep -Eq "[1-9]\d* failures \([1-9]\d* unexpected\)" "$log_file"; then + echo "xcodebuild failed with unexpected failures." 1>&2 + return 65 + fi +} + if [[ "$xcode_major" -lt 15 ]]; then ios_flags=( -sdk 'iphonesimulator' From 653ab45c0aec096dff5f913ab7ba4d1e75af52de Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 20 Nov 2024 13:22:17 -0500 Subject: [PATCH 57/98] [Infra] Use macos-13 + Xcode 14 in inappmessaging workflow (#14128) --- .github/workflows/inappmessaging.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index 9464fa3a245..a21f02eb13e 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -45,13 +45,13 @@ jobs: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' # TODO(#12770): Update to macos-14 when tests are updated for Xcode 15. - runs-on: macos-12 + runs-on: macos-13 strategy: matrix: # TODO(#8682): Reenable iPad after fixing Xcode 13 test failures. # platform: [iOS, iPad] platform: [iOS] - + xcode: [Xcode_14.2] steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 @@ -60,6 +60,8 @@ jobs: - uses: ruby/setup-ruby@v1 - name: Setup Bundler run: scripts/setup_bundler.sh + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Prereqs run: scripts/install_prereqs.sh InAppMessaging ${{ matrix.platform }} xcodebuild - name: Build and test From cb0bc7741812b1d8dec6dcd5f8f4ac0193d56aed Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:38:06 -0500 Subject: [PATCH 58/98] [Auth] Remove unnecessary throws on internal methods (#14154) --- FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift | 6 +++--- .../Swift/SystemService/AuthStoredUserManager.swift | 6 +++--- FirebaseAuth/Tests/Unit/AuthUserDefaultsTests.swift | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift b/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift index 54be969dc01..a3e6719eb95 100644 --- a/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift +++ b/FirebaseAuth/Sources/Swift/Storage/AuthUserDefaults.swift @@ -35,7 +35,7 @@ class AuthUserDefaults { storage = UserDefaults() } - func data(forKey key: String) throws -> Data? { + func data(forKey key: String) -> Data? { guard let allData = storage.persistentDomain(forName: persistentDomainName) else { return nil } if let data = allData[key] as? Data { @@ -44,13 +44,13 @@ class AuthUserDefaults { return nil } - func setData(_ data: Data, forKey key: String) throws { + func setData(_ data: Data, forKey key: String) { var allData = storage.persistentDomain(forName: persistentDomainName) ?? [:] allData[key] = data storage.setPersistentDomain(allData, forName: persistentDomainName) } - func removeData(forKey key: String) throws { + func removeData(forKey key: String) { guard var allData = storage.persistentDomain(forName: persistentDomainName) else { return } allData.removeValue(forKey: key) storage.setPersistentDomain(allData, forName: persistentDomainName) diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthStoredUserManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthStoredUserManager.swift index 5517ddc3fa1..2fe9d3de389 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthStoredUserManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthStoredUserManager.swift @@ -43,7 +43,7 @@ class AuthStoredUserManager { /// Get the user access group stored locally. /// - Returns: The stored user access group; otherwise, `nil`. func getStoredUserAccessGroup() -> String? { - if let data = try? userDefaults.data(forKey: Self.storedUserAccessGroupKey) { + if let data = userDefaults.data(forKey: Self.storedUserAccessGroupKey) { let userAccessGroup = String(data: data, encoding: .utf8) return userAccessGroup } else { @@ -55,9 +55,9 @@ class AuthStoredUserManager { /// - Parameter accessGroup: The access group to be store. func setStoredUserAccessGroup(accessGroup: String?) { if let data = accessGroup?.data(using: .utf8) { - try? userDefaults.setData(data, forKey: Self.storedUserAccessGroupKey) + userDefaults.setData(data, forKey: Self.storedUserAccessGroupKey) } else { - try? userDefaults.removeData(forKey: Self.storedUserAccessGroupKey) + userDefaults.removeData(forKey: Self.storedUserAccessGroupKey) } } diff --git a/FirebaseAuth/Tests/Unit/AuthUserDefaultsTests.swift b/FirebaseAuth/Tests/Unit/AuthUserDefaultsTests.swift index be41068fbda..15d9780beaa 100644 --- a/FirebaseAuth/Tests/Unit/AuthUserDefaultsTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthUserDefaultsTests.swift @@ -32,7 +32,7 @@ class AuthUserDefaultsTests: XCTestCase { @brief Tests reading non-existing storage item. */ func testReadNonexisting() throws { - XCTAssertNil(try storage.data(forKey: kKey)) + XCTAssertNil(storage.data(forKey: kKey)) } /** @fn testWriteRead @@ -40,7 +40,7 @@ class AuthUserDefaultsTests: XCTestCase { */ func testWriteRead() throws { try storage.setData(dataFromString(kData), forKey: kKey) - XCTAssertEqual(try storage.data(forKey: kKey), try dataFromString(kData)) + XCTAssertEqual(storage.data(forKey: kKey), try dataFromString(kData)) } /** @fn testOverwrite @@ -50,7 +50,7 @@ class AuthUserDefaultsTests: XCTestCase { let kOtherData = "OTHER_DATA" try storage.setData(dataFromString(kData), forKey: kKey) try storage.setData(dataFromString(kOtherData), forKey: kKey) - XCTAssertEqual(try storage.data(forKey: kKey), try dataFromString(kOtherData)) + XCTAssertEqual(storage.data(forKey: kKey), try dataFromString(kOtherData)) } /** @fn testRemove @@ -67,7 +67,7 @@ class AuthUserDefaultsTests: XCTestCase { func testServices() throws { try storage.setData(dataFromString(kData), forKey: kKey) storage = AuthUserDefaults(service: "Other service") - XCTAssertNil(try storage.data(forKey: kKey)) + XCTAssertNil(storage.data(forKey: kKey)) } /** @fn testStandardUserDefaults From 7cfb06faef729b3c3ad68454ff8c0c94965b7f20 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 20 Nov 2024 19:54:07 -0800 Subject: [PATCH 59/98] Remove dead code from FirebaseRemoteConfig (#14153) --- .../Sources/Private/RCNConfigSettings.h | 8 - .../Sources/RCNConfigDBManager.h | 13 +- .../Sources/RCNConfigDBManager.m | 88 +--------- .../Sources/RCNConfigSettings.m | 46 +---- .../Tests/Unit/RCNConfigDBManagerTest.m | 33 ---- .../Tests/Unit/RCNConfigSettingsTest.m | 165 ------------------ 6 files changed, 7 insertions(+), 346 deletions(-) diff --git a/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h b/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h index 26b82172681..9530dee817c 100644 --- a/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h +++ b/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h @@ -55,11 +55,6 @@ /// Custom variable (aka App context digest). This is the pending custom variables request before /// fetching. @property(nonatomic, copy) NSDictionary *customVariables; -/// Cached internal metadata from internal metadata table. It contains customized information such -/// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time -/// interval. Client has the default value of each parameters, they are only saved in -/// internalMetadata if they have been customize by developers. -@property(nonatomic, readonly, copy) NSDictionary *internalMetadata; /// Device conditions since last successful fetch from the backend. Device conditions including /// app /// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for @@ -122,9 +117,6 @@ /// Returns metadata from metadata table. - (NSDictionary *)loadConfigFromMetadataTable; -/// Updates internal content with the latest successful config response. -- (void)updateInternalContentWithResponse:(NSDictionary *)response; - /// Updates the metadata table with the current fetch status. /// @param fetchSuccess True if fetch was successful. - (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess diff --git a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h index 97ca03af6e7..e22b40d3779 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h +++ b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h @@ -70,10 +70,6 @@ typedef void (^RCNDBLoadCompletion)(BOOL success, /// start. Config settings include success/failure fetch times, device contenxt, app context, etc. - (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier namespace:(NSString *)namespace; -/// Load internal metadata from internal metadata table, such as customized HTTP connection/read -/// timeout, throttling time interval and number limit of throttling, etc. -/// This call needs to be blocking to ensure throttling works during apps starts. -- (NSDictionary *)loadInternalMetadataTable; /// Load experiment from experiment table. /// @param handler The callback when reading from DB is complete. - (void)loadExperimentWithCompletionHandler:(RCNDBCompletion)handler; @@ -90,10 +86,6 @@ typedef void (^RCNDBLoadCompletion)(BOOL success, - (void)insertMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)source completionHandler:(RCNDBCompletion)handler; -/// Insert a record in internal metadata table. -/// @param values Values to be inserted. -- (void)insertInternalMetadataTableWithValues:(NSArray *)values - completionHandler:(RCNDBCompletion)handler; /// Insert experiment data in experiment table. /// @param key The key of experiment data belongs to, which are defined in /// RCNConfigDefines.h. @@ -125,11 +117,10 @@ typedef void (^RCNDBLoadCompletion)(BOOL success, - (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p bundleIdentifier:(NSString *)bundleIdentifier fromSource:(RCNDBSource)source; -/// Remove all the records of given package name and namespace from metadata/internal metadata DB +/// Remove all the records of given package name and namespace from metadata DB /// before updating new values from response. - (void)deleteRecordWithBundleIdentifier:(NSString *)bundlerIdentifier - namespace:(NSString *)namespace - isInternalDB:(BOOL)isInternalDB; + namespace:(NSString *)namespace; /// Remove all the records from a config content table. - (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source; diff --git a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m index 57ee0258515..161f678b8d6 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m @@ -28,7 +28,6 @@ #define RCNTableNameMainDefault "main_default" #define RCNTableNameMetadataDeprecated "fetch_metadata" #define RCNTableNameMetadata "fetch_metadata_v2" -#define RCNTableNameInternalMetadata "internal_metadata" #define RCNTableNameExperiment "experiment" #define RCNTableNamePersonalization "personalization" #define RCNTableNameRollout "rollout" @@ -278,10 +277,6 @@ - (BOOL)createTableSchema { "success_fetch_time BLOB, failure_fetch_time BLOB, last_fetch_status INTEGER, " "last_fetch_error INTEGER, last_apply_time INTEGER, last_set_defaults_time INTEGER)"; - static const char *createTableInternalMetadata = - "create TABLE IF NOT EXISTS " RCNTableNameInternalMetadata - " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)"; - static const char *createTableExperiment = "create TABLE IF NOT EXISTS " RCNTableNameExperiment " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)"; static const char *createTablePersonalization = @@ -293,7 +288,6 @@ - (BOOL)createTableSchema { return [self executeQuery:createTableMain] && [self executeQuery:createTableMainActive] && [self executeQuery:createTableMainDefault] && [self executeQuery:createTableMetadata] && - [self executeQuery:createTableInternalMetadata] && [self executeQuery:createTableExperiment] && [self executeQuery:createTablePersonalization] && [self executeQuery:createTableRollout]; } @@ -471,48 +465,6 @@ - (BOOL)insertMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)sour return YES; } -- (void)insertInternalMetadataTableWithValues:(NSArray *)values - completionHandler:(RCNDBCompletion)handler { - __weak RCNConfigDBManager *weakSelf = self; - dispatch_async(_databaseOperationQueue, ^{ - BOOL success = [weakSelf insertInternalMetadataWithValues:values]; - if (handler) { - dispatch_async(dispatch_get_main_queue(), ^{ - handler(success, nil); - }); - } - }); -} - -- (BOOL)insertInternalMetadataWithValues:(NSArray *)values { - RCN_MUST_NOT_BE_MAIN_THREAD(); - if (values.count != 2) { - return NO; - } - const char *SQL = - "INSERT OR REPLACE INTO " RCNTableNameInternalMetadata " (key, value) values (?, ?)"; - sqlite3_stmt *statement = [self prepareSQL:SQL]; - if (!statement) { - return NO; - } - NSString *aString = values[0]; - if (![self bindStringToStatement:statement index:1 string:aString]) { - [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; - return NO; - } - NSData *blobData = values[1]; - if (sqlite3_bind_blob(statement, 2, blobData.bytes, (int)blobData.length, NULL) != SQLITE_OK) { - [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; - return NO; - } - if (sqlite3_step(statement) != SQLITE_DONE) { - [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; - return NO; - } - sqlite3_finalize(statement); - return YES; -} - - (void)insertExperimentTableWithKey:(NSString *)key value:(NSData *)serializedValue completionHandler:(RCNDBCompletion)handler { @@ -1039,34 +991,6 @@ - (NSData *)loadPersonalizationTableFromKey:(int)key { return results[0]; } -- (NSDictionary *)loadInternalMetadataTable { - __block NSMutableDictionary *internalMetadataTableResult; - __weak RCNConfigDBManager *weakSelf = self; - dispatch_sync(_databaseOperationQueue, ^{ - internalMetadataTableResult = [weakSelf loadInternalMetadataTableInternal]; - }); - return internalMetadataTableResult; -} - -- (NSMutableDictionary *)loadInternalMetadataTableInternal { - NSMutableDictionary *internalMetadata = [[NSMutableDictionary alloc] init]; - const char *SQL = "SELECT key, value FROM " RCNTableNameInternalMetadata; - sqlite3_stmt *statement = [self prepareSQL:SQL]; - if (!statement) { - return nil; - } - - while (sqlite3_step(statement) == SQLITE_ROW) { - NSString *key = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)]; - - NSData *dataValue = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 1) - length:sqlite3_column_bytes(statement, 1)]; - internalMetadata[key] = dataValue; - } - sqlite3_finalize(statement); - return internalMetadata; -} - /// This method is only meant to be called at init time. The underlying logic will need to be /// reevaluated if the assumption changes at a later time. - (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier @@ -1178,20 +1102,16 @@ - (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p } - (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier - namespace:(NSString *)namespace - isInternalDB:(BOOL)isInternalDB { + namespace:(NSString *)namespace { __weak RCNConfigDBManager *weakSelf = self; dispatch_async(_databaseOperationQueue, ^{ RCNConfigDBManager *strongSelf = weakSelf; if (!strongSelf) { return; } - const char *SQL = "DELETE FROM " RCNTableNameInternalMetadata " WHERE key LIKE ?"; - NSArray *params = @[ bundleIdentifier ]; - if (!isInternalDB) { - SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ? and namespace = ?"; - params = @[ bundleIdentifier, namespace ]; - } + const char *SQL = + "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ? and namespace = ?"; + NSArray *params = @[ bundleIdentifier, namespace ]; [strongSelf executeQuery:SQL withParams:params]; }); } diff --git a/FirebaseRemoteConfig/Sources/RCNConfigSettings.m b/FirebaseRemoteConfig/Sources/RCNConfigSettings.m index 48e414e2f83..69848f872f7 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigSettings.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigSettings.m @@ -45,11 +45,6 @@ @interface RCNConfigSettings () { /// Custom variables (aka App context digest). This is the pending custom variables request before /// fetching. NSMutableDictionary *_customVariables; - /// Cached internal metadata from internal metadata table. It contains customized information such - /// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time - /// interval. Client has the default value of each parameters, they are only saved in - /// internalMetadata if they have been customize by developers. - NSMutableDictionary *_internalMetadata; /// Last fetch status. FIRRemoteConfigFetchStatus _lastFetchStatus; /// Last fetch Error. @@ -66,8 +61,6 @@ @interface RCNConfigSettings () { NSString *_googleAppID; /// The user defaults manager scoped to this RC instance of FIRApp and namespace. RCNUserDefaultsManager *_userDefaultsManager; - /// The timestamp of last eTag update. - NSTimeInterval _lastETagUpdateTime; } @end @@ -93,11 +86,6 @@ - (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager _successFetchTimes = [[NSMutableArray alloc] init]; _failureFetchTimes = [[NSMutableArray alloc] init]; _DBManager = manager; - - _internalMetadata = [[_DBManager loadInternalMetadataTable] mutableCopy]; - if (!_internalMetadata) { - _internalMetadata = [[NSMutableDictionary alloc] init]; - } _userDefaultsManager = [[RCNUserDefaultsManager alloc] initWithAppName:appName bundleID:_bundleIdentifier namespace:_FIRNamespace]; @@ -184,32 +172,6 @@ - (NSDictionary *)loadConfigFromMetadataTable { } #pragma mark - update DB/cached - -// Update internal metadata content to cache and DB. -- (void)updateInternalContentWithResponse:(NSDictionary *)response { - // Remove all the keys with current package name. - [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier - namespace:_FIRNamespace - isInternalDB:YES]; - - for (NSString *key in _internalMetadata.allKeys) { - if ([key hasPrefix:_bundleIdentifier]) { - [_internalMetadata removeObjectForKey:key]; - } - } - - for (NSString *entry in response) { - NSData *val = [response[entry] dataUsingEncoding:NSUTF8StringEncoding]; - NSArray *values = @[ entry, val ]; - _internalMetadata[entry] = response[entry]; - [self updateInternalMetadataTableWithValues:values]; - } -} - -- (void)updateInternalMetadataTableWithValues:(NSArray *)values { - [_DBManager insertInternalMetadataTableWithValues:values completionHandler:nil]; -} - /// If the last fetch was not successful, update the (exponential backoff) period that we wait until /// fetching again. Any subsequent fetch requests will be checked and allowed only if past this /// throttle end time. @@ -310,9 +272,7 @@ - (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch { } - (void)updateMetadataTable { - [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier - namespace:_FIRNamespace - isInternalDB:NO]; + [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier namespace:_FIRNamespace]; NSError *error; // Objects to be serialized cannot be invalid. if (!_bundleIdentifier) { @@ -472,10 +432,6 @@ - (NSDictionary *)customVariables { return [_customVariables copy]; } -- (NSDictionary *)internalMetadata { - return [_internalMetadata copy]; -} - - (NSDictionary *)deviceContext { return [_deviceContext copy]; } diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNConfigDBManagerTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNConfigDBManagerTest.m index 773af690935..09c577346bb 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNConfigDBManagerTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNConfigDBManagerTest.m @@ -155,39 +155,6 @@ - (void)testWriteAndLoadMainTableResult { }]; } -- (void)testWriteAndLoadInternalMetadataResult { - XCTestExpectation *loadConfigContentExpectation = [self - expectationWithDescription:@"Write and read internal metadata in database successfully"]; - __block int count = 0; - for (int i = 0; i <= 100; ++i) { - // check DB write correctly - RCNDBCompletion insertCompletion = ^void(BOOL success, NSDictionary *result) { - count++; - XCTAssertTrue(success); - if (count == 100) { - // check DB read correctly - NSDictionary *result = [self->_DBManager loadInternalMetadataTable]; - NSString *stringValue = [[NSString alloc] initWithData:result[@"key100"] - encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(stringValue, @"value100"); - if (success) { - [loadConfigContentExpectation fulfill]; - } - } - }; - NSString *value = [NSString stringWithFormat:@"value%d", i]; - NSString *key = [NSString stringWithFormat:@"key%d", i]; - - NSArray *values = @[ key, [value dataUsingEncoding:NSUTF8StringEncoding] ]; - [_DBManager insertInternalMetadataTableWithValues:values completionHandler:insertCompletion]; - } - - [self waitForExpectationsWithTimeout:_expectionTimeout - handler:^(NSError *error) { - XCTAssertNil(error); - }]; -} - - (void)testWriteAndLoadMetadataResult { XCTestExpectation *writeAndLoadMetadataExpectation = [self expectationWithDescription:@"Write and load metadata in database successfully"]; diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNConfigSettingsTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNConfigSettingsTest.m index a5ed22a8bb6..045e0cdf247 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNConfigSettingsTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNConfigSettingsTest.m @@ -25,7 +25,6 @@ @interface RCNConfigSettings (ExposedTestCase) - (RCNConfigFetchRequest *)nextRequestWithUserProperties:(NSDictionary *)userProperties fetchedConfig:(NSDictionary *)fetchedConfig; -- (void)updateInternalContentWithResponse:(RCNConfigFetchResponse *)response; - (void)updateConfigContentWithResponse:(RCNConfigFetchResponse *)response; - (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch; - (BOOL)hasCachedData; @@ -54,170 +53,6 @@ - (void)testCrashShouldNotHappenWithoutMainBundleID { } #ifdef FIX_OR_DELETE -- (void)testUpdateInternalMetadata { - RCNConfigFetchResponse *response = [[RCNConfigFetchResponse alloc] init]; - // Mock internal metadata array with all_packages prefix key - response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{ - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNHTTPConnectionTimeoutInMillisecondsKey] : @"50", - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNHTTPReadTimeoutInMillisecondsKey] : @"2000000", - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNThrottledSuccessFetchTimeIntervalInSecondsKey] : @"300", - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNThrottledSuccessFetchCountKey] : @"-6", - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNThrottledFailureFetchTimeIntervalInSecondsKey] : @"10000000", - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNThrottledFailureFetchCountKey] : @"21", - - }]; - [_mockSettings updateInternalContentWithResponse:response]; - XCTAssertEqual( - [_mockSettings internalMetadataValueForKey:RCNHTTPConnectionTimeoutInMillisecondsKey - minValue:RCNHTTPConnectionTimeoutInMillisecondsMin - maxValue:RCNHTTPConnectionTimeoutInMillisecondsMax - defaultValue:RCNHTTPConnectionTimeoutInMillisecondsDefault], - RCNHTTPConnectionTimeoutInMillisecondsMin, - @"HTTP Connection Timeout must be within the range."); - XCTAssertEqual( - [_mockSettings internalMetadataValueForKey:RCNHTTPReadTimeoutInMillisecondsKey - minValue:RCNHTTPReadTimeoutInMillisecondsMin - maxValue:RCNHTTPReadTimeoutInMillisecondsMax - defaultValue:RCNHTTPReadTimeoutInMillisecondsDefault], - RCNHTTPReadTimeoutInMillisecondsMax, @"HTTP Read Timeout must be within the range"); - XCTAssertEqual( - [_mockSettings - internalMetadataValueForKey:RCNThrottledSuccessFetchTimeIntervalInSecondsKey - minValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMin - maxValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMax - defaultValue:RCNThrottledSuccessFetchTimeIntervalInSecondsDefault], - RCNThrottledSuccessFetchTimeIntervalInSecondsMin, - @"Throttling success internal must be within the range"); - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - RCNThrottledSuccessFetchCountMin); - XCTAssertEqual( - [_mockSettings - internalMetadataValueForKey:RCNThrottledFailureFetchTimeIntervalInSecondsKey - minValue:RCNThrottledFailureFetchTimeIntervalInSecondsMin - maxValue:RCNThrottledFailureFetchTimeIntervalInSecondsMax - defaultValue:RCNThrottledFailureFetchTimeIntervalInSecondsDefault], - RCNThrottledFailureFetchTimeIntervalInSecondsMax); - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledFailureFetchCountKey - minValue:RCNThrottledFailureFetchCountMin - maxValue:RCNThrottledFailureFetchCountMax - defaultValue:RCNThrottledFailureFetchCountDefault], - RCNThrottledFailureFetchCountMax); - - // Mock internal metadata array with bundle_identifier prefix key. - // bundle_identifier prefixed key should override all_packages prefix key - NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; - response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{ - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, - RCNHTTPConnectionTimeoutInMillisecondsKey] : @"70000", - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNHTTPReadTimeoutInMillisecondsKey] : - @"70000", - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, - RCNThrottledSuccessFetchTimeIntervalInSecondsKey] : @"1800", - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNThrottledSuccessFetchCountKey] : - @"100", - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, - RCNThrottledFailureFetchTimeIntervalInSecondsKey] : @"1800", - [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNThrottledFailureFetchCountKey] : @"0", - }]; - [_mockSettings updateInternalContentWithResponse:response]; - - XCTAssertEqual( - [_mockSettings internalMetadataValueForKey:RCNHTTPConnectionTimeoutInMillisecondsKey - minValue:RCNHTTPConnectionTimeoutInMillisecondsMin - maxValue:RCNHTTPConnectionTimeoutInMillisecondsMax - defaultValue:RCNHTTPConnectionTimeoutInMillisecondsDefault], - 70000); - XCTAssertEqual( - [_mockSettings internalMetadataValueForKey:RCNHTTPReadTimeoutInMillisecondsKey - minValue:RCNHTTPReadTimeoutInMillisecondsMin - maxValue:RCNHTTPReadTimeoutInMillisecondsMax - defaultValue:RCNHTTPReadTimeoutInMillisecondsDefault], - 70000); - XCTAssertEqual( - [_mockSettings - internalMetadataValueForKey:RCNThrottledSuccessFetchTimeIntervalInSecondsKey - minValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMin - maxValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMax - defaultValue:RCNThrottledSuccessFetchTimeIntervalInSecondsDefault], - 1800); - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - 20); - - XCTAssertEqual( - [_mockSettings - internalMetadataValueForKey:RCNThrottledFailureFetchTimeIntervalInSecondsKey - minValue:RCNThrottledFailureFetchTimeIntervalInSecondsMin - maxValue:RCNThrottledFailureFetchTimeIntervalInSecondsMax - defaultValue:RCNThrottledFailureFetchTimeIntervalInSecondsDefault], - 1800); - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledFailureFetchCountKey - minValue:RCNThrottledFailureFetchCountMin - maxValue:RCNThrottledFailureFetchCountMax - defaultValue:RCNThrottledFailureFetchCountDefault], - 1); -} - -- (void)testInternalMetadataOverride { - // Mock response after fetching. - RCNConfigFetchResponse *response = [[RCNConfigFetchResponse alloc] init]; - NSString *onePackageKey = - [NSString stringWithFormat:@"%@:%@", [[NSBundle mainBundle] bundleIdentifier], - RCNThrottledSuccessFetchCountKey]; - NSString *allPackageKey = - [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix, - RCNThrottledSuccessFetchCountKey]; - - [_mockSettings updateInternalContentWithResponse:response]; - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - RCNThrottledSuccessFetchCountDefault, - @"Fetch with no internal metadata, must return default value."); - - response.internalMetadataArray = - [RCNTestUtilities entryArrayWithKeyValuePair:@{onePackageKey : @"8", allPackageKey : @"9"}]; - [_mockSettings updateInternalContentWithResponse:response]; - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - 8, @"Fetch with both keys, must return the one with package key."); - - [response.internalMetadataArray removeAllObjects]; - [_mockSettings updateInternalContentWithResponse:response]; - XCTAssertEqual( - [_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - 9, @"Fetch with no internal metadata, must return the one with previous all_packages key."); - - [response.internalMetadataArray removeAllObjects]; - response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{ - onePackageKey : @"6", - }]; - - [_mockSettings updateInternalContentWithResponse:response]; - XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey - minValue:RCNThrottledSuccessFetchCountMin - maxValue:RCNThrottledSuccessFetchCountMax - defaultValue:RCNThrottledSuccessFetchCountDefault], - 6, @"Fetch with one package key, must return the one with package key."); -} - - (void)testThrottlingFresh { NSTimeInterval endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp]; NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; From 700fd6803d50275be326c356b400704f2ea8b481 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:09:36 -0500 Subject: [PATCH 60/98] [Firestore] Add conditonal Sendability conformance to ServerTimestamp (#14162) --- Firestore/CHANGELOG.md | 4 ++++ Firestore/Swift/Source/Codable/ServerTimestamp.swift | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index 5781296165b..61c08250d85 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Add conditional `Sendable` conformance so `ServerTimestamp` is + `Sendable` if `T` is `Sendable`. (#14042) + # 11.4.0 - [changed] Prepare Firestore cache to support session token. diff --git a/Firestore/Swift/Source/Codable/ServerTimestamp.swift b/Firestore/Swift/Source/Codable/ServerTimestamp.swift index fe6bbd696db..753878c16d5 100644 --- a/Firestore/Swift/Source/Codable/ServerTimestamp.swift +++ b/Firestore/Swift/Source/Codable/ServerTimestamp.swift @@ -105,3 +105,5 @@ public struct ServerTimestamp: Codable extension ServerTimestamp: Equatable where Value: Equatable {} extension ServerTimestamp: Hashable where Value: Hashable {} + +extension ServerTimestamp: Sendable where Value: Sendable {} From 19f36aa38c3dc1258a0103efcc06e094a266ffa6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:38:10 -0500 Subject: [PATCH 61/98] [Auth] Add objc attribute to UserInfoImpl so legacy decoding works (#14169) --- FirebaseAuth/CHANGELOG.md | 2 ++ FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift | 1 + 2 files changed, 3 insertions(+) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 36eca32322a..a66c8f1d9ee 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -2,6 +2,8 @@ - [fixed] Restore Firebase 10 behavior by synchronizing access to the `Auth.currentUser` API. This resolves some Firebase 11 issues where the current user is unexpectedly `nil` at startup. +- [fixed] Restore Firebase 10 decoding behavior to prevent user provider data + from being decoded as `nil`. (#14011) # 11.5.0 - [fixed] Restore pre-Firebase 11 decoding behavior to prevent users getting diff --git a/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift b/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift index a1fe938ae03..23ef4c8de9a 100644 --- a/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift +++ b/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift @@ -18,6 +18,7 @@ import Foundation extension UserInfoImpl: NSSecureCoding {} @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +@objc(FIRUserInfoImpl) // objc Needed for decoding old versions class UserInfoImpl: NSObject, UserInfo { /// A convenience factory method for constructing a `UserInfo` instance from data /// returned by the getAccountInfo endpoint. From f527552dba979ad1463bc0eeb44369a3df7d75b3 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 26 Nov 2024 08:10:22 -0800 Subject: [PATCH 62/98] 11.6.0 Changelog updates (#14173) --- FirebaseAuth/CHANGELOG.md | 2 +- FirebasePerformance/CHANGELOG.md | 2 +- FirebaseVertexAI/CHANGELOG.md | 2 +- Firestore/CHANGELOG.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index a66c8f1d9ee..93cccc30b48 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.6.0 - [fixed] Restore Firebase 10 behavior by synchronizing access to the `Auth.currentUser` API. This resolves some Firebase 11 issues where the current user is unexpectedly `nil` at startup. diff --git a/FirebasePerformance/CHANGELOG.md b/FirebasePerformance/CHANGELOG.md index a5679e943cc..6ac0cee960b 100644 --- a/FirebasePerformance/CHANGELOG.md +++ b/FirebasePerformance/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.6.0 - [fixed] Fix a crash related to registering for notifications when the app is between foreground or background states. (#13174) # 11.5.0 diff --git a/FirebaseVertexAI/CHANGELOG.md b/FirebaseVertexAI/CHANGELOG.md index a7c1b1aaba5..469cfdb0e5f 100644 --- a/FirebaseVertexAI/CHANGELOG.md +++ b/FirebaseVertexAI/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.6.0 - [changed] The token counts from `GenerativeModel.countTokens(...)` now include tokens from the schema for JSON output and function calling; reported token counts will now be higher if using these features. diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index 61c08250d85..ee7ea12f87f 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 11.6.0 - [fixed] Add conditional `Sendable` conformance so `ServerTimestamp` is `Sendable` if `T` is `Sendable`. (#14042) From a834162078ac518afdf2010e3ec9d8dd9eb493a0 Mon Sep 17 00:00:00 2001 From: Liubin Jiang <56564857+Xiaoshouzi-gh@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:50:41 -0800 Subject: [PATCH 63/98] Update CHANGELOG.md for rCE phone auth feature (#14171) --- FirebaseAuth/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 93cccc30b48..c91a44333f6 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,6 @@ # 11.6.0 +- [added] Added reCAPTCHA Enterprise support for app verification during phone + authentication for Firebase Authentication (#14114) - [fixed] Restore Firebase 10 behavior by synchronizing access to the `Auth.currentUser` API. This resolves some Firebase 11 issues where the current user is unexpectedly `nil` at startup. From e3c1d07d960cc1c0bbee565c6fb3660dbe820d0b Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:53:21 -0500 Subject: [PATCH 64/98] [Infra] Don't require firestore check on docs changed (#14176) --- .github/workflows/firestore.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 72d14573a8a..ab5c94a6303 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -30,16 +30,22 @@ jobs: # Only when this is not a scheduled run if: github.event_name != 'schedule' outputs: - changed: ${{ steps.changes.outputs.changed }} + changed: ${{ steps.firestore_src_changes.outputs.sources || steps.related_changes.outputs.other_changes }} steps: - uses: dorny/paths-filter@v2 - id: changes + id: firestore_src_changes with: + predicate-quantifier: 'every' filters: | - changed: + sources: # Firestore sources - 'Firestore/**' - + - '!**/*.md' + - uses: dorny/paths-filter@v2 + id: related_changes + with: + filters: | + other_changes: # Interop headers - 'FirebaseAuth/Interop/*.h' From e23f688fba53efa53c56af113ca9284cad01fb1a Mon Sep 17 00:00:00 2001 From: Liubin Jiang <56564857+Xiaoshouzi-gh@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:56:57 -0800 Subject: [PATCH 65/98] add reCAPTCHA enterprise support on phone auth and phone MFA (#14114) Co-authored-by: Srushti Vaidya Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 2 +- .../AuthProvider/PhoneAuthProvider.swift | 281 +++++++++--- .../Sources/Swift/Backend/AuthBackend.swift | 1 + .../Enroll/StartMFAEnrollmentRequest.swift | 23 + .../SignIn/StartMFASignInRequest.swift | 11 + .../AuthProtoStartMFAPhoneRequestInfo.swift | 28 ++ .../RPC/SendVerificationTokenRequest.swift | 30 +- .../Swift/Utilities/AuthErrorUtils.swift | 4 + .../Utilities/AuthRecaptchaVerifier.swift | 121 +++-- .../PhoneAuthViewController.swift | 34 +- .../Unit/Fakes/FakeBackendRPCIssuer.swift | 28 +- .../Tests/Unit/GetRecaptchaConfigTests.swift | 34 +- .../Tests/Unit/PhoneAuthProviderTests.swift | 413 ++++++++++++++---- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 1 + .../Unit/StartMFAEnrollmentRequestTests.swift | 58 +++ .../Unit/StartMFASignInRequestTests.swift | 89 ++++ 16 files changed, 934 insertions(+), 224 deletions(-) create mode 100644 FirebaseAuth/Tests/Unit/StartMFASignInRequestTests.swift diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 3600a90c478..b8abba0a933 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -2307,7 +2307,7 @@ extension Auth: AuthInterop { action: AuthRecaptchaAction) async throws -> T .Response { let recaptchaVerifier = AuthRecaptchaVerifier.shared(auth: self) - if recaptchaVerifier.enablementStatus(forProvider: AuthRecaptchaProvider.password) { + if recaptchaVerifier.enablementStatus(forProvider: AuthRecaptchaProvider.password) != .off { try await recaptchaVerifier.injectRecaptchaFields(request: request, provider: AuthRecaptchaProvider.password, action: action) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 2a1de385aa4..3e72368126c 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -22,6 +22,10 @@ import Foundation @objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject { /// A string constant identifying the phone identity provider. @objc public static let id = "phone" + private static let recaptchaVersion = "RECAPTCHA_ENTERPRISE" + private static let clientType = "CLIENT_TYPE_IOS" + private static let fakeCaptchaResponse = "NO_RECAPTCHA" + #if os(iOS) /// Returns an instance of `PhoneAuthProvider` for the default `Auth` object. @objc(provider) open class func provider() -> PhoneAuthProvider { @@ -72,23 +76,19 @@ import Foundation uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession? = nil, completion: ((_: String?, _: Error?) -> Void)?) { - guard AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, - urlTypes: auth.mainBundleUrlTypes) else { - fatalError( - "Please register custom URL scheme \(callbackScheme) in the app's Info.plist file." - ) - } - kAuthGlobalWorkQueue.async { - Task { - do { - let verificationID = try await self.internalVerify( - phoneNumber: phoneNumber, - uiDelegate: uiDelegate, - multiFactorSession: multiFactorSession - ) - Auth.wrapMainAsync(callback: completion, withParam: verificationID, error: nil) - } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Task { + do { + let verificationID = try await verifyPhoneNumber( + phoneNumber, + uiDelegate: uiDelegate, + multiFactorSession: multiFactorSession + ) + await MainActor.run { + completion?(verificationID, nil) + } + } catch { + await MainActor.run { + completion?(nil, error) } } } @@ -107,16 +107,19 @@ import Foundation uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession? = nil) async throws -> String { - return try await withCheckedThrowingContinuation { continuation in - self.verifyPhoneNumber(phoneNumber, - uiDelegate: uiDelegate, - multiFactorSession: multiFactorSession) { result, error in - if let error { - continuation.resume(throwing: error) - } else if let result { - continuation.resume(returning: result) - } - } + guard AuthWebUtils.isCallbackSchemeRegistered(forCustomURLScheme: callbackScheme, + urlTypes: auth.mainBundleUrlTypes) else { + fatalError( + "Please register custom URL scheme \(callbackScheme) in the app's Info.plist file." + ) + } + + if let verificationID = try await internalVerify(phoneNumber: phoneNumber, + uiDelegate: uiDelegate, + multiFactorSession: multiFactorSession) { + return verificationID + } else { + throw AuthErrorUtils.invalidVerificationIDError(message: "Invalid verification ID") } } @@ -133,11 +136,22 @@ import Foundation uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession?, completion: ((_: String?, _: Error?) -> Void)?) { - multiFactorSession?.multiFactorInfo = multiFactorInfo - verifyPhoneNumber(multiFactorInfo.phoneNumber, - uiDelegate: uiDelegate, - multiFactorSession: multiFactorSession, - completion: completion) + Task { + do { + let verificationID = try await verifyPhoneNumber( + with: multiFactorInfo, + uiDelegate: uiDelegate, + multiFactorSession: multiFactorSession + ) + await MainActor.run { + completion?(verificationID, nil) + } + } catch { + await MainActor.run { + completion?(nil, error) + } + } + } } /// Verify ownership of the second factor phone number by the current user. @@ -152,17 +166,10 @@ import Foundation open func verifyPhoneNumber(with multiFactorInfo: PhoneMultiFactorInfo, uiDelegate: AuthUIDelegate? = nil, multiFactorSession: MultiFactorSession?) async throws -> String { - return try await withCheckedThrowingContinuation { continuation in - self.verifyPhoneNumber(with: multiFactorInfo, - uiDelegate: uiDelegate, - multiFactorSession: multiFactorSession) { result, error in - if let error { - continuation.resume(throwing: error) - } else if let result { - continuation.resume(returning: result) - } - } - } + multiFactorSession?.multiFactorInfo = multiFactorInfo + return try await verifyPhoneNumber(multiFactorInfo.phoneNumber, + uiDelegate: uiDelegate, + multiFactorSession: multiFactorSession) } /// Creates an `AuthCredential` for the phone number provider identified by the @@ -185,7 +192,7 @@ import Foundation uiDelegate: AuthUIDelegate?, multiFactorSession: MultiFactorSession? = nil) async throws -> String? { - guard phoneNumber.count > 0 else { + guard !phoneNumber.isEmpty else { throw AuthErrorUtils.missingPhoneNumberError(message: nil) } guard let manager = auth.notificationManager else { @@ -194,10 +201,62 @@ import Foundation guard await manager.checkNotificationForwarding() else { throw AuthErrorUtils.notificationNotForwardedError() } - return try await verifyClAndSendVerificationCode(toPhoneNumber: phoneNumber, - retryOnInvalidAppCredential: true, - multiFactorSession: multiFactorSession, - uiDelegate: uiDelegate) + + let recaptchaVerifier = AuthRecaptchaVerifier.shared(auth: auth) + try await recaptchaVerifier.retrieveRecaptchaConfig(forceRefresh: true) + + switch recaptchaVerifier.enablementStatus(forProvider: .phone) { + case .off: + return try await verifyClAndSendVerificationCode( + toPhoneNumber: phoneNumber, + retryOnInvalidAppCredential: true, + multiFactorSession: multiFactorSession, + uiDelegate: uiDelegate + ) + case .audit: + return try await verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: phoneNumber, + retryOnInvalidAppCredential: true, + multiFactorSession: multiFactorSession, + uiDelegate: uiDelegate, + recaptchaVerifier: recaptchaVerifier + ) + case .enforce: + return try await verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: phoneNumber, + retryOnInvalidAppCredential: false, + multiFactorSession: multiFactorSession, + uiDelegate: uiDelegate, + recaptchaVerifier: recaptchaVerifier + ) + } + } + + func verifyClAndSendVerificationCodeWithRecaptcha(toPhoneNumber phoneNumber: String, + retryOnInvalidAppCredential: Bool, + uiDelegate: AuthUIDelegate?, + recaptchaVerifier: AuthRecaptchaVerifier) async throws + -> String? { + let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, + codeIdentity: CodeIdentity.empty, + requestConfiguration: auth + .requestConfiguration) + do { + try await recaptchaVerifier.injectRecaptchaFields( + request: request, + provider: .phone, + action: .sendVerificationCode + ) + let response = try await auth.backend.call(with: request) + return response.verificationID + } catch { + return try await handleVerifyErrorWithRetry(error: error, + phoneNumber: phoneNumber, + retryOnInvalidAppCredential: retryOnInvalidAppCredential, + multiFactorSession: nil, + uiDelegate: uiDelegate, + auditFallback: true) + } } /// Starts the flow to verify the client via silent push notification. @@ -206,36 +265,116 @@ import Foundation /// - Parameter phoneNumber: The phone number to be verified. /// - Parameter callback: The callback to be invoked on the global work queue when the flow is /// finished. - private func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, - retryOnInvalidAppCredential: Bool, - uiDelegate: AuthUIDelegate?) async throws + func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, + retryOnInvalidAppCredential: Bool, + uiDelegate: AuthUIDelegate?, + auditFallback: Bool = false) async throws -> String? { let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate) let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, codeIdentity: codeIdentity, requestConfiguration: auth .requestConfiguration) - + if auditFallback { + request.injectRecaptchaFields( + recaptchaResponse: PhoneAuthProvider.fakeCaptchaResponse, + recaptchaVersion: PhoneAuthProvider.recaptchaVersion + ) + } do { let response = try await auth.backend.call(with: request) return response.verificationID } catch { - return try await handleVerifyErrorWithRetry(error: error, - phoneNumber: phoneNumber, - retryOnInvalidAppCredential: retryOnInvalidAppCredential, - multiFactorSession: nil, - uiDelegate: uiDelegate) + return try await handleVerifyErrorWithRetry( + error: error, + phoneNumber: phoneNumber, + retryOnInvalidAppCredential: retryOnInvalidAppCredential, + multiFactorSession: nil, + uiDelegate: uiDelegate, + auditFallback: auditFallback + ) + } + } + + /// Starts the flow to verify the client via silent push notification. This is used in both + /// .Audit and .Enforce mode + /// - Parameter retryOnInvalidAppCredential: Whether or not the flow should be retried if an + /// AuthErrorCodeInvalidAppCredential error is returned from the backend. + /// - Parameter phoneNumber: The phone number to be verified. + private func verifyClAndSendVerificationCodeWithRecaptcha(toPhoneNumber phoneNumber: String, + retryOnInvalidAppCredential: Bool, + multiFactorSession session: MultiFactorSession?, + uiDelegate: AuthUIDelegate?, + recaptchaVerifier: AuthRecaptchaVerifier) async throws + -> String? { + if let settings = auth.settings, + settings.isAppVerificationDisabledForTesting { + let request = SendVerificationCodeRequest( + phoneNumber: phoneNumber, + codeIdentity: CodeIdentity.empty, + requestConfiguration: auth.requestConfiguration + ) + let response = try await auth.backend.call(with: request) + return response.verificationID + } + guard let session else { + return try await verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: phoneNumber, + retryOnInvalidAppCredential: retryOnInvalidAppCredential, + uiDelegate: uiDelegate, + recaptchaVerifier: recaptchaVerifier + ) + } + let startMFARequestInfo = AuthProtoStartMFAPhoneRequestInfo(phoneNumber: phoneNumber, + codeIdentity: CodeIdentity.empty) + do { + if let idToken = session.idToken { + let request = StartMFAEnrollmentRequest(idToken: idToken, + enrollmentInfo: startMFARequestInfo, + requestConfiguration: auth.requestConfiguration) + try await recaptchaVerifier.injectRecaptchaFields( + request: request, + provider: .phone, + action: .mfaSmsEnrollment + ) + let response = try await auth.backend.call(with: request) + return response.phoneSessionInfo?.sessionInfo + } else { + let request = StartMFASignInRequest(MFAPendingCredential: session.mfaPendingCredential, + MFAEnrollmentID: session.multiFactorInfo?.uid, + signInInfo: startMFARequestInfo, + requestConfiguration: auth.requestConfiguration) + try await recaptchaVerifier.injectRecaptchaFields( + request: request, + provider: .phone, + action: .mfaSmsSignIn + ) + let response = try await auth.backend.call(with: request) + return response.responseInfo?.sessionInfo + } + } catch { + // For Audit fallback only after rCE check failed + return try await handleVerifyErrorWithRetry( + error: error, + phoneNumber: phoneNumber, + retryOnInvalidAppCredential: retryOnInvalidAppCredential, + multiFactorSession: session, + uiDelegate: uiDelegate, + auditFallback: true + ) } } /// Starts the flow to verify the client via silent push notification. - /// - Parameter retryOnInvalidAppCredential: Whether of not the flow should be retried if an + /// This method is called in Audit fallback flow with "NO_RECAPTCHA" fake token and Off flow + /// - Parameter retryOnInvalidAppCredential: Whether or not the flow should be retried if an /// AuthErrorCodeInvalidAppCredential error is returned from the backend. /// - Parameter phoneNumber: The phone number to be verified. private func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, retryOnInvalidAppCredential: Bool, multiFactorSession session: MultiFactorSession?, - uiDelegate: AuthUIDelegate?) async throws + uiDelegate: AuthUIDelegate?, + auditFallback: Bool = false) async throws -> String? { if let settings = auth.settings, settings.isAppVerificationDisabledForTesting { @@ -249,15 +388,25 @@ import Foundation return response.verificationID } guard let session else { + // Phone MFA flow return try await verifyClAndSendVerificationCode( toPhoneNumber: phoneNumber, retryOnInvalidAppCredential: retryOnInvalidAppCredential, - uiDelegate: uiDelegate + uiDelegate: uiDelegate, + auditFallback: auditFallback ) } + // MFA flows let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate) let startMFARequestInfo = AuthProtoStartMFAPhoneRequestInfo(phoneNumber: phoneNumber, codeIdentity: codeIdentity) + if auditFallback { + startMFARequestInfo.injectRecaptchaFields( + recaptchaResponse: PhoneAuthProvider.fakeCaptchaResponse, + recaptchaVersion: PhoneAuthProvider.recaptchaVersion, + clientType: PhoneAuthProvider.clientType + ) + } do { if let idToken = session.idToken { let request = StartMFAEnrollmentRequest(idToken: idToken, @@ -280,23 +429,27 @@ import Foundation phoneNumber: phoneNumber, retryOnInvalidAppCredential: retryOnInvalidAppCredential, multiFactorSession: session, - uiDelegate: uiDelegate + uiDelegate: uiDelegate, + auditFallback: auditFallback ) } } + /// This method is only called when Audit failed on rCE on invalid-app-credential exception private func handleVerifyErrorWithRetry(error: Error, phoneNumber: String, retryOnInvalidAppCredential: Bool, multiFactorSession session: MultiFactorSession?, - uiDelegate: AuthUIDelegate?) async throws -> String? { + uiDelegate: AuthUIDelegate?, + auditFallback: Bool = false) async throws -> String? { if (error as NSError).code == AuthErrorCode.invalidAppCredential.rawValue { if retryOnInvalidAppCredential { auth.appCredentialManager.clearCredential() return try await verifyClAndSendVerificationCode(toPhoneNumber: phoneNumber, retryOnInvalidAppCredential: false, multiFactorSession: session, - uiDelegate: uiDelegate) + uiDelegate: uiDelegate, + auditFallback: auditFallback) } throw AuthErrorUtils.unexpectedResponse(deserializedResponse: nil, underlyingError: error) } @@ -474,6 +627,7 @@ import Foundation private let auth: Auth private let callbackScheme: String private let usingClientIDScheme: Bool + private var recaptchaVerifier: AuthRecaptchaVerifier? init(auth: Auth) { self.auth = auth @@ -494,6 +648,7 @@ import Foundation return } callbackScheme = "" + recaptchaVerifier = AuthRecaptchaVerifier.shared(auth: auth) } private let kAuthTypeVerifyApp = "verifyApp" diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index f981701b98e..61be56b09ca 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -177,6 +177,7 @@ final class AuthBackend: AuthBackendProtocol { withJSONObject: postBody, options: JSONWritingOptions ) + if bodyData == nil { // This is an untested case. This happens exclusively when there is an error in the // framework implementation of dataWithJSONObject:options:error:. This shouldn't normally diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift index 467733768fc..a36c7bb3bc6 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/Enroll/StartMFAEnrollmentRequest.swift @@ -16,6 +16,18 @@ import Foundation private let kStartMFAEnrollmentEndPoint = "accounts/mfaEnrollment:start" +/// The key for the "clientType" value in the request. +private let kClientType = "clientType" + +/// The key for the reCAPTCHAToken parameter in the request. +private let kreCAPTCHATokenKey = "recaptchaToken" + +/// The key for the "captchaResponse" value in the request. +private let kCaptchaResponseKey = "captchaResponse" + +/// The key for the "recaptchaVersion" value in the request. +private let kRecaptchaVersion = "recaptchaVersion" + /// The key for the tenant id value in the request. private let kTenantIDKey = "tenantId" @@ -79,4 +91,15 @@ class StartMFAEnrollmentRequest: IdentityToolkitRequest, AuthRPCRequest { } return body } + + func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String) { + // reCAPTCHA check is only available for phone based MFA + if let phoneEnrollmentInfo { + phoneEnrollmentInfo.injectRecaptchaFields( + recaptchaResponse: recaptchaResponse, + recaptchaVersion: recaptchaVersion, + clientType: clientType + ) + } + } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift index 82e1a1721bd..ae28451fb9e 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInRequest.swift @@ -57,4 +57,15 @@ class StartMFASignInRequest: IdentityToolkitRequest, AuthRPCRequest { } return body } + + func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String) { + // reCAPTCHA check is only available for phone based MFA + if let signInInfo { + signInInfo.injectRecaptchaFields( + recaptchaResponse: recaptchaResponse, + recaptchaVersion: recaptchaVersion, + clientType: clientType + ) + } + } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/Proto/Phone/AuthProtoStartMFAPhoneRequestInfo.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/Proto/Phone/AuthProtoStartMFAPhoneRequestInfo.swift index 274a7b97883..87d0d03f5be 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/Proto/Phone/AuthProtoStartMFAPhoneRequestInfo.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/Proto/Phone/AuthProtoStartMFAPhoneRequestInfo.swift @@ -26,6 +26,15 @@ private let kSecretKey = "iosSecret" /// The key for the reCAPTCHAToken parameter in the request. private let kreCAPTCHATokenKey = "recaptchaToken" +/// The key for the "captchaResponse" value in the request. +private let kCaptchaResponseKey = "captchaResponse" + +/// The key for the "recaptchaVersion" value in the request. +private let kRecaptchaVersion = "recaptchaVersion" + +/// The key for the "clientType" value in the request. +private let kClientType = "clientType" + class AuthProtoStartMFAPhoneRequestInfo: NSObject, AuthProto { required init(dictionary: [String: AnyHashable]) { fatalError() @@ -33,6 +42,9 @@ class AuthProtoStartMFAPhoneRequestInfo: NSObject, AuthProto { var phoneNumber: String? var codeIdentity: CodeIdentity + var captchaResponse: String? + var recaptchaVersion: String? + var clientType: String? init(phoneNumber: String?, codeIdentity: CodeIdentity) { self.phoneNumber = phoneNumber self.codeIdentity = codeIdentity @@ -43,6 +55,15 @@ class AuthProtoStartMFAPhoneRequestInfo: NSObject, AuthProto { if let phoneNumber = phoneNumber { dict[kPhoneNumberKey] = phoneNumber } + if let captchaResponse = captchaResponse { + dict[kCaptchaResponseKey] = captchaResponse + } + if let recaptchaVersion = recaptchaVersion { + dict[kRecaptchaVersion] = recaptchaVersion + } + if let clientType = clientType { + dict[kClientType] = clientType + } switch codeIdentity { case let .credential(appCredential): dict[kReceiptKey] = appCredential.receipt @@ -54,4 +75,11 @@ class AuthProtoStartMFAPhoneRequestInfo: NSObject, AuthProto { } return dict } + + func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String, + clientType: String?) { + captchaResponse = recaptchaResponse + self.recaptchaVersion = recaptchaVersion + self.clientType = clientType + } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift index a87ff833c10..729cf1d200d 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenRequest.swift @@ -29,11 +29,20 @@ private let kSecretKey = "iosSecret" /// The key for the reCAPTCHAToken parameter in the request. private let kreCAPTCHATokenKey = "recaptchaToken" +/// The key for the "clientType" value in the request. +private let kClientType = "clientType" + +/// The key for the "captchaResponse" value in the request. +private let kCaptchaResponseKey = "captchaResponse" + +/// The key for the "recaptchaVersion" value in the request. +private let kRecaptchaVersion = "recaptchaVersion" + /// The key for the tenant id value in the request. private let kTenantIDKey = "tenantId" /// A verification code can be an appCredential or a reCaptcha Token -enum CodeIdentity { +enum CodeIdentity: Equatable { case credential(AuthAppCredential) case recaptcha(String) case empty @@ -50,6 +59,12 @@ class SendVerificationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { /// verification code. let codeIdentity: CodeIdentity + /// Response to the captcha. + var captchaResponse: String? + + /// The reCAPTCHA version. + var recaptchaVersion: String? + init(phoneNumber: String, codeIdentity: CodeIdentity, requestConfiguration: AuthRequestConfiguration) { self.phoneNumber = phoneNumber @@ -71,10 +86,21 @@ class SendVerificationCodeRequest: IdentityToolkitRequest, AuthRPCRequest { postBody[kreCAPTCHATokenKey] = reCAPTCHAToken case .empty: break } - + if let captchaResponse { + postBody[kCaptchaResponseKey] = captchaResponse + } + if let recaptchaVersion { + postBody[kRecaptchaVersion] = recaptchaVersion + } if let tenantID { postBody[kTenantIDKey] = tenantID } + postBody[kClientType] = clientType return postBody } + + func injectRecaptchaFields(recaptchaResponse: String?, recaptchaVersion: String) { + captchaResponse = recaptchaResponse + self.recaptchaVersion = recaptchaVersion + } } diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift index 6e6a1a74353..ee397bfc670 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift @@ -203,6 +203,10 @@ class AuthErrorUtils { error(code: .missingAndroidPackageName, message: message) } + static func invalidRecaptchaTokenError() -> Error { + error(code: .invalidRecaptchaToken) + } + static func unauthorizedDomainError(message: String?) -> Error { error(code: .unauthorizedDomain, message: message) } diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index 859496fac82..7fd2c8c092c 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -23,24 +23,47 @@ @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class AuthRecaptchaConfig { - let siteKey: String - let enablementStatus: [String: Bool] + var siteKey: String? + let enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus] - init(siteKey: String, enablementStatus: [String: Bool]) { + init(siteKey: String? = nil, + enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus]) { self.siteKey = siteKey self.enablementStatus = enablementStatus } } - enum AuthRecaptchaProvider { - case password + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) + enum AuthRecaptchaEnablementStatus: String, CaseIterable { + case enforce = "ENFORCE" + case audit = "AUDIT" + case off = "OFF" + + // Convenience property for mapping values + var stringValue: String { rawValue } } - enum AuthRecaptchaAction { + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) + enum AuthRecaptchaProvider: String, CaseIterable { + case password = "EMAIL_PASSWORD_PROVIDER" + case phone = "PHONE_PROVIDER" + + // Convenience property for mapping values + var stringValue: String { rawValue } + } + + @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) + enum AuthRecaptchaAction: String { case defaultAction case signInWithPassword case getOobCode case signUpPassword + case sendVerificationCode + case mfaSmsSignIn + case mfaSmsEnrollment + + // Convenience property for mapping values + var stringValue: String { rawValue } } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @@ -49,14 +72,9 @@ private(set) var agentConfig: AuthRecaptchaConfig? private(set) var tenantConfigs: [String: AuthRecaptchaConfig] = [:] private(set) var recaptchaClient: RCARecaptchaClientProtocol? - - private static let _shared = AuthRecaptchaVerifier() - private let providerToStringMap = [AuthRecaptchaProvider.password: "EMAIL_PASSWORD_PROVIDER"] - private let actionToStringMap = [AuthRecaptchaAction.signInWithPassword: "signInWithPassword", - AuthRecaptchaAction.getOobCode: "getOobCode", - AuthRecaptchaAction.signUpPassword: "signUpPassword"] + private static var _shared = AuthRecaptchaVerifier() private let kRecaptchaVersion = "RECAPTCHA_ENTERPRISE" - private init() {} + init() {} class func shared(auth: Auth?) -> AuthRecaptchaVerifier { if _shared.auth != auth { @@ -67,6 +85,12 @@ return _shared } + /// This function is only for testing. + class func setShared(_ instance: AuthRecaptchaVerifier, auth: Auth?) { + _shared = instance + _ = shared(auth: auth) + } + func siteKey() -> String? { if let tenantID = auth?.tenantID { if let config = tenantConfigs[tenantID] { @@ -77,22 +101,17 @@ return agentConfig?.siteKey } - func enablementStatus(forProvider provider: AuthRecaptchaProvider) -> Bool { - guard let providerString = providerToStringMap[provider] else { - return false - } - if let tenantID = auth?.tenantID { - guard let tenantConfig = tenantConfigs[tenantID], - let status = tenantConfig.enablementStatus[providerString] else { - return false - } + func enablementStatus(forProvider provider: AuthRecaptchaProvider) + -> AuthRecaptchaEnablementStatus { + if let tenantID = auth?.tenantID, + let tenantConfig = tenantConfigs[tenantID], + let status = tenantConfig.enablementStatus[provider] { return status - } else { - guard let agentConfig, - let status = agentConfig.enablementStatus[providerString] else { - return false - } + } else if let agentConfig = agentConfig, + let status = agentConfig.enablementStatus[provider] { return status + } else { + return AuthRecaptchaEnablementStatus.off } } @@ -101,7 +120,7 @@ guard let siteKey = siteKey() else { throw AuthErrorUtils.recaptchaSiteKeyMissing() } - let actionString = actionToStringMap[action] ?? "" + let actionString = action.stringValue #if !(COCOAPODS || SWIFT_PACKAGE) // No recaptcha on internal build system. return actionString @@ -156,30 +175,40 @@ let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration) let response = try await auth.backend.call(with: request) AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.") - // Response's site key is of the format projects//keys/' - guard let keys = response.recaptchaKey?.components(separatedBy: "/"), - keys.count == 4 else { - throw AuthErrorUtils.error(code: .recaptchaNotEnabled, message: "Invalid siteKey") - } - let siteKey = keys[3] - var enablementStatus: [String: Bool] = [:] + try await parseRecaptchaConfigFromResponse(response: response) + } + + func parseRecaptchaConfigFromResponse(response: GetRecaptchaConfigResponse) async throws { + var enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus] = [:] + var isRecaptchaEnabled = false if let enforcementState = response.enforcementState { for state in enforcementState { - if let provider = state["provider"], - provider == providerToStringMap[AuthRecaptchaProvider.password] { - if let enforcement = state["enforcementState"] { - if enforcement == "ENFORCE" || enforcement == "AUDIT" { - enablementStatus[provider] = true - } else if enforcement == "OFF" { - enablementStatus[provider] = false - } - } + guard let providerString = state["provider"], + let enforcementString = state["enforcementState"], + let provider = AuthRecaptchaProvider(rawValue: providerString), + let enforcement = AuthRecaptchaEnablementStatus(rawValue: enforcementString) else { + continue // Skip to the next state in the loop + } + enablementStatus[provider] = enforcement + if enforcement != .off { + isRecaptchaEnabled = true } } } + var siteKey = "" + // Response's site key is of the format projects//keys/' + if isRecaptchaEnabled { + if let recaptchaKey = response.recaptchaKey { + let keys = recaptchaKey.components(separatedBy: "/") + if keys.count != 4 { + throw AuthErrorUtils.error(code: .recaptchaNotEnabled, message: "Invalid siteKey") + } + siteKey = keys[3] + } + } let config = AuthRecaptchaConfig(siteKey: siteKey, enablementStatus: enablementStatus) - if let tenantID = auth.tenantID { + if let tenantID = auth?.tenantID { tenantConfigs[tenantID] = config } else { agentConfig = config @@ -190,7 +219,7 @@ provider: AuthRecaptchaProvider, action: AuthRecaptchaAction) async throws { try await retrieveRecaptchaConfig(forceRefresh: false) - if enablementStatus(forProvider: provider) { + if enablementStatus(forProvider: provider) != .off { let token = try await verify(forceRefresh: false, action: action) request.injectRecaptchaFields(recaptchaResponse: token, recaptchaVersion: kRecaptchaVersion) } else { diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift index f1a29ded31d..a95b0fd8ca2 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/OtherAuthMethodControllers/PhoneAuthViewController.swift @@ -30,17 +30,18 @@ class PhoneAuthViewController: OtherAuthViewController { private func phoneAuthLogin(_ phoneNumber: String) { let phoneNumber = String(format: "+%@", phoneNumber) - PhoneAuthProvider.provider() - .verifyPhoneNumber(phoneNumber, uiDelegate: nil) { verificationID, error in - guard error == nil else { return self.displayError(error) } - - guard let verificationID = verificationID else { return } - self.presentPhoneAuthController { verificationCode in - let credential = PhoneAuthProvider.provider() - .credential(withVerificationID: verificationID, verificationCode: verificationCode) - self.signin(with: credential) - } + Task { + do { + let phoneAuthProvider = PhoneAuthProvider.provider() + let verificationID = try await phoneAuthProvider.verifyPhoneNumber(phoneNumber) + let verificationCode = try await getVerificationCode() + let credential = phoneAuthProvider.credential(withVerificationID: verificationID, + verificationCode: verificationCode) + self.signin(with: credential) + } catch { + self.displayError(error) } + } } private func signin(with credential: PhoneAuthCredential) { @@ -74,4 +75,17 @@ class PhoneAuthViewController: OtherAuthViewController { present(phoneAuthController, animated: true, completion: nil) } + + private func getVerificationCode() async throws -> String { + return try await withCheckedThrowingContinuation { continuation in + self.presentPhoneAuthController { code in + if code != "" { + continuation.resume(returning: code) + } else { + // Cancelled + continuation.resume(throwing: NSError()) + } + } + } + } } diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift index 9131a19f98f..ceca635dacf 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift @@ -74,7 +74,8 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda var fakeSecureTokenServiceJSON: [String: AnyHashable]? var secureTokenNetworkError: NSError? var secureTokenErrorString: String? - var recaptchaSiteKey = "unset recaptcha siteKey" + var recaptchaSiteKey = "projects/fakeProjectId/keys/mockSiteKey" + var rceMode: String = "OFF" func asyncCallToURL(with request: T, body: Data?, contentType: String) async -> (Data?, Error?) @@ -120,9 +121,28 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda } return } else if let _ = request as? GetRecaptchaConfigRequest { - guard let _ = try? respond(withJSON: ["recaptchaKey": recaptchaSiteKey]) - else { - fatalError("GetRecaptchaConfigRequest respond failed") + if rceMode != "OFF" { // Check if reCAPTCHA is enabled + let recaptchaKey = recaptchaSiteKey // iOS key from your config + let enforcementState = [ + ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": rceMode], + ["provider": "PHONE_PROVIDER", "enforcementState": rceMode], + ] + guard let _ = try? respond(withJSON: [ + "recaptchaKey": recaptchaKey, + "recaptchaEnforcementState": enforcementState, + ]) else { + fatalError("GetRecaptchaConfigRequest respond failed") + } + } else { // reCAPTCHA OFF + let enforcementState = [ + ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": "OFF"], + ["provider": "PHONE_PROVIDER", "enforcementState": "OFF"], + ] + guard let _ = try? respond(withJSON: [ + "recaptchaEnforcementState": enforcementState, + ]) else { + fatalError("GetRecaptchaConfigRequest respond failed") + } } return } else if let _ = request as? SecureTokenRequest { diff --git a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift index 6638d6bfcc1..bf0b1cd5c38 100644 --- a/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift +++ b/FirebaseAuth/Tests/Unit/GetRecaptchaConfigTests.swift @@ -39,16 +39,42 @@ class GetRecaptchaConfigTests: RPCBaseTests { ) } - /** @fn testSuccessfulGetRecaptchaConfigRequest - @brief This test simulates a successful @c getRecaptchaConfig Flow. + /** @fn testSuccessfulGetRecaptchaConfigRequestRecaptchaEnabled + @brief This test simulates a successful @c getRecaptchaConfig Flow when recaptcha is enabled. */ - func testSuccessfulGetRecaptchaConfigRequest() async throws { + func testSuccessfulGetRecaptchaConfigRequestRecaptchaEnabled() async throws { let kTestRecaptchaKey = "projects/123/keys/456" let request = GetRecaptchaConfigRequest(requestConfiguration: makeRequestConfiguration()) rpcIssuer.recaptchaSiteKey = kTestRecaptchaKey + let enforcementMode = "AUDIT" + rpcIssuer.rceMode = enforcementMode let response = try await authBackend.call(with: request) XCTAssertEqual(response.recaptchaKey, kTestRecaptchaKey) - XCTAssertNil(response.enforcementState) + XCTAssertEqual( + response.enforcementState, + [ + ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": enforcementMode], + ["provider": "PHONE_PROVIDER", "enforcementState": enforcementMode], + ] + ) + } + + /** @fn testSuccessfulGetRecaptchaConfigRequestRecaptchaDisabled + @brief This test simulates a successful @c getRecaptchaConfig Flow when recaptcha is disabled. + */ + func testSuccessfulGetRecaptchaConfigRequestRecaptchaDisabled() async throws { + let request = GetRecaptchaConfigRequest(requestConfiguration: makeRequestConfiguration()) + let enforcementMode = "OFF" + rpcIssuer.rceMode = enforcementMode + let response = try await authBackend.call(with: request) + XCTAssertEqual(response.recaptchaKey, nil) + XCTAssertEqual( + response.enforcementState, + [ + ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": enforcementMode], + ["provider": "PHONE_PROVIDER", "enforcementState": enforcementMode], + ] + ) } } diff --git a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift index 9a319ea9755..fd7291f6820 100644 --- a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift @@ -41,6 +41,8 @@ private let kVerificationIDKey = "sessionInfo" private let kFakeEncodedFirebaseAppID = "app-1-123456789-ios-123abc456def" private let kFakeReCAPTCHAToken = "fakeReCAPTCHAToken" + private let kCaptchaResponse: String = "captchaResponse" + private let kRecaptchaVersion: String = "RECAPTCHA_ENTERPRISE" static var auth: Auth? @@ -62,89 +64,276 @@ } /** @fn testVerifyEmptyPhoneNumber - @brief Tests a failed invocation @c verifyPhoneNumber:completion: because an empty phone + @brief Tests a failed invocation verifyPhoneNumber because an empty phone number was provided. */ - func testVerifyEmptyPhoneNumber() throws { + func testVerifyEmptyPhoneNumber() async throws { initApp(#function) let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) let provider = PhoneAuthProvider.provider(auth: auth) - let expectation = self.expectation(description: #function) - // Empty phone number is checked on the client side so no backend RPC is faked. - provider.verifyPhoneNumber("", uiDelegate: nil) { verificationID, error in - XCTAssertNotNil(error) - XCTAssertNil(verificationID) - XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.missingPhoneNumber.rawValue) - expectation.fulfill() + do { + _ = try await provider.verifyPhoneNumber("") + XCTFail("Expected an error, but verification succeeded.") + } catch { + XCTAssertEqual((error as NSError).code, AuthErrorCode.missingPhoneNumber.rawValue) } - waitForExpectations(timeout: 5) } /** @fn testVerifyInvalidPhoneNumber @brief Tests a failed invocation @c verifyPhoneNumber:completion: because an invalid phone number was provided. */ - func testVerifyInvalidPhoneNumber() throws { - try internalTestVerify(errorString: "INVALID_PHONE_NUMBER", - errorCode: AuthErrorCode.invalidPhoneNumber.rawValue, - function: #function) + func testVerifyInvalidPhoneNumber() async throws { + try await internalTestVerify(errorString: "INVALID_PHONE_NUMBER", + errorCode: AuthErrorCode.invalidPhoneNumber.rawValue, + function: #function) } /** @fn testVerifyPhoneNumber @brief Tests a successful invocation of @c verifyPhoneNumber:completion:. */ - func testVerifyPhoneNumber() throws { - try internalTestVerify(function: #function) + func testVerifyPhoneNumber() async throws { + try await internalTestVerify(function: #function) + } + + /** + @fn testVerifyPhoneNumberWithRceEnforce + @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise enforced + */ + func testVerifyPhoneNumberWithRceEnforceSuccess() async throws { + initApp(#function) + let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) + // TODO: Figure out how to mock objective C's FIRRecaptchaGetToken response + let provider = PhoneAuthProvider.provider(auth: auth) + let mockVerifier = FakeAuthRecaptchaVerifier(captchaResponse: kCaptchaResponse) + AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) + rpcIssuer.rceMode = "ENFORCE" + let requestExpectation = expectation(description: "verifyRequester") + rpcIssuer?.verifyRequester = { request in + XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) + XCTAssertEqual(request.captchaResponse, self.kCaptchaResponse) + XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") + XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) + requestExpectation.fulfill() + do { + try self.rpcIssuer? + .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) + } catch { + XCTFail("Failure sending response: \(error)") + } + } + do { + let result = try await provider.verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: kTestPhoneNumber, + retryOnInvalidAppCredential: false, + uiDelegate: nil, + recaptchaVerifier: mockVerifier + ) + XCTAssertEqual(result, kTestVerificationID) + } catch { + XCTFail("Unexpected error") + } + await fulfillment(of: [requestExpectation], timeout: 5.0) + } + + /** + @fn testVerifyPhoneNumberWithRceEnforceInvalidRecaptcha + @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise enforced + */ + func testVerifyPhoneNumberWithRceEnforceInvalidRecaptcha() async throws { + initApp(#function) + let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) + // TODO: Figure out how to mock objective C's FIRRecaptchaGetToken response + let provider = PhoneAuthProvider.provider(auth: auth) + let mockVerifier = FakeAuthRecaptchaVerifier() + AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) + rpcIssuer.rceMode = "ENFORCE" + let requestExpectation = expectation(description: "verifyRequester") + rpcIssuer?.verifyRequester = { request in + XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) + XCTAssertEqual(request.captchaResponse, "NO_RECAPTCHA") + XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") + XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) + requestExpectation.fulfill() + do { + try self.rpcIssuer? + .respond( + serverErrorMessage: "INVALID_RECAPTCHA_TOKEN", + error: AuthErrorUtils.invalidRecaptchaTokenError() as NSError + ) + } catch { + XCTFail("Failure sending response: \(error)") + } + } + do { + _ = try await provider.verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: kTestPhoneNumber, + retryOnInvalidAppCredential: false, + uiDelegate: nil, + recaptchaVerifier: mockVerifier + ) + // XCTAssertEqual(result, kTestVerificationID) + } catch { + // Traverse the nested error to find the root cause + let underlyingError = (error as NSError).userInfo[NSUnderlyingErrorKey] as? NSError + let rootError = underlyingError?.userInfo[NSUnderlyingErrorKey] as? NSError + + // Compare the root error code to the expected error code + XCTAssertEqual(rootError?.code, AuthErrorCode.invalidRecaptchaToken.code.rawValue) + } + await fulfillment(of: [requestExpectation], timeout: 5.0) + } + + /** + @fn testVerifyPhoneNumberWithRceEnforceSDKNotLinked + @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise enforced + */ + func testVerifyPhoneNumberWithRceEnforceRecaptchaSDKNotLinked() async throws { + return try await testRecaptchaFlowError( + function: #function, + rceError: AuthErrorUtils.recaptchaSDKNotLinkedError() + ) + } + + /** + @fn testVerifyPhoneNumberWithRceEnforceSDKNotLinked + @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise enforced + */ + func testVerifyPhoneNumberWithRceEnforceRecaptchaActionCreationFailed() async throws { + return try await testRecaptchaFlowError( + function: #function, + rceError: AuthErrorUtils.recaptchaActionCreationFailed() + ) + } + + /// @fn testVerifyPhoneNumberWithRceAudit + /// @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise in + /// audit mode + func testVerifyPhoneNumberWithRceAuditSuccess() async throws { + initApp(#function) + let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) + let provider = PhoneAuthProvider.provider(auth: auth) + let mockVerifier = FakeAuthRecaptchaVerifier(captchaResponse: kCaptchaResponse) + AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) + rpcIssuer.rceMode = "AUDIT" + let requestExpectation = expectation(description: "verifyRequester") + rpcIssuer?.verifyRequester = { request in + XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) + XCTAssertEqual(request.captchaResponse, self.kCaptchaResponse) + XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") + XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) + requestExpectation.fulfill() + do { + try self.rpcIssuer? + .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) + } catch { + XCTFail("Failure sending response: \(error)") + } + } + do { + let result = try await provider.verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: kTestPhoneNumber, + retryOnInvalidAppCredential: false, + uiDelegate: nil, + recaptchaVerifier: mockVerifier + ) + XCTAssertEqual(result, kTestVerificationID) + } catch { + XCTFail("Unexpected error") + } + await fulfillment(of: [requestExpectation], timeout: 5.0) + } + + /// @fn testVerifyPhoneNumberWithRceAuditInvalidRecaptcha + /// @brief Tests a successful invocation of @c verifyPhoneNumber with recaptcha enterprise in + /// audit mode + func testVerifyPhoneNumberWithRceAuditInvalidRecaptcha() async throws { + initApp(#function) + let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) + let provider = PhoneAuthProvider.provider(auth: auth) + let mockVerifier = FakeAuthRecaptchaVerifier() + AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) + rpcIssuer.rceMode = "AUDIT" + let requestExpectation = expectation(description: "verifyRequester") + rpcIssuer?.verifyRequester = { request in + XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) + XCTAssertEqual(request.captchaResponse, "NO_RECAPTCHA") + XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") + XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) + requestExpectation.fulfill() + do { + try self.rpcIssuer? + .respond( + serverErrorMessage: "INVALID_RECAPTCHA_TOKEN", + error: AuthErrorUtils.invalidRecaptchaTokenError() as NSError + ) + } catch { + XCTFail("Failure sending response: \(error)") + } + } + do { + _ = try await provider.verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: kTestPhoneNumber, + retryOnInvalidAppCredential: false, + uiDelegate: nil, + recaptchaVerifier: mockVerifier + ) + } catch { + let underlyingError = (error as NSError).userInfo[NSUnderlyingErrorKey] as? NSError + let rootError = underlyingError?.userInfo[NSUnderlyingErrorKey] as? NSError + XCTAssertEqual(rootError?.code, AuthErrorCode.invalidRecaptchaToken.code.rawValue) + } + await fulfillment(of: [requestExpectation], timeout: 5.0) } /** @fn testVerifyPhoneNumberInTestMode @brief Tests a successful invocation of @c verifyPhoneNumber:completion: when app verification is disabled. */ - func testVerifyPhoneNumberInTestMode() throws { - try internalTestVerify(function: #function, testMode: true) + func testVerifyPhoneNumberInTestMode() async throws { + try await internalTestVerify(function: #function, testMode: true) } /** @fn testVerifyPhoneNumberInTestModeFailure @brief Tests a failed invocation of @c verifyPhoneNumber:completion: when app verification is disabled. */ - func testVerifyPhoneNumberInTestModeFailure() throws { - try internalTestVerify(errorString: "INVALID_PHONE_NUMBER", - errorCode: AuthErrorCode.invalidPhoneNumber.rawValue, - function: #function, testMode: true) + func testVerifyPhoneNumberInTestModeFailure() async throws { + try await internalTestVerify(errorString: "INVALID_PHONE_NUMBER", + errorCode: AuthErrorCode.invalidPhoneNumber.rawValue, + function: #function, testMode: true) } /** @fn testVerifyPhoneNumberUIDelegateFirebaseAppIdFlow @brief Tests a successful invocation of @c verifyPhoneNumber:UIDelegate:completion:. */ - func testVerifyPhoneNumberUIDelegateFirebaseAppIdFlow() throws { - try internalTestVerify(function: #function, reCAPTCHAfallback: true) + func testVerifyPhoneNumberUIDelegateFirebaseAppIdFlow() async throws { + try await internalTestVerify(function: #function, reCAPTCHAfallback: true) } /** @fn testVerifyPhoneNumberUIDelegateFirebaseAppIdWhileClientIdPresentFlow @brief Tests a successful invocation of @c verifyPhoneNumber:UIDelegate:completion: when the client ID is present in the plist file, but the encoded app ID is the registered custom URL scheme. */ - func testVerifyPhoneNumberUIDelegateFirebaseAppIdWhileClientIdPresentFlow() throws { - try internalTestVerify(function: #function, useClientID: true, - bothClientAndAppID: true, reCAPTCHAfallback: true) + func testVerifyPhoneNumberUIDelegateFirebaseAppIdWhileClientIdPresentFlow() async throws { + try await internalTestVerify(function: #function, useClientID: true, + bothClientAndAppID: true, reCAPTCHAfallback: true) } /** @fn testVerifyPhoneNumberUIDelegateClientIdFlow @brief Tests a successful invocation of @c verifyPhoneNumber:UIDelegate:completion:. */ - func testVerifyPhoneNumberUIDelegateClientIdFlow() throws { - try internalTestVerify(function: #function, useClientID: true, reCAPTCHAfallback: true) + func testVerifyPhoneNumberUIDelegateClientIdFlow() async throws { + try await internalTestVerify(function: #function, useClientID: true, reCAPTCHAfallback: true) } /** @fn testVerifyPhoneNumberUIDelegateInvalidClientID @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an invalid client ID error. */ - func testVerifyPhoneNumberUIDelegateInvalidClientID() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateInvalidClientID() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringInvalidClientID, errorCode: AuthErrorCode.invalidClientID.rawValue, function: #function, @@ -157,8 +346,8 @@ @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in a web network request failed error. */ - func testVerifyPhoneNumberUIDelegateWebNetworkRequestFailed() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateWebNetworkRequestFailed() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringWebNetworkRequestFailed, errorCode: AuthErrorCode.webNetworkRequestFailed.rawValue, function: #function, @@ -171,8 +360,8 @@ @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in a web internal error. */ - func testVerifyPhoneNumberUIDelegateWebInternalError() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateWebInternalError() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringWebInternalError, errorCode: AuthErrorCode.webInternalError.rawValue, function: #function, @@ -182,11 +371,11 @@ } /** @fn testVerifyPhoneNumberUIDelegateUnexpectedError - @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an - invalid client ID. + @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an + invalid client ID. */ - func testVerifyPhoneNumberUIDelegateUnexpectedError() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateUnexpectedError() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringUnknownError, errorCode: AuthErrorCode.webSignInUserInteractionFailure.rawValue, function: #function, @@ -196,12 +385,12 @@ } /** @fn testVerifyPhoneNumberUIDelegateUnstructuredError - @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an - error being surfaced with a default NSLocalizedFailureReasonErrorKey due to an unexpected - structure of the error response. + @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an + error being surfaced with a default NSLocalizedFailureReasonErrorKey due to an unexpected + structure of the error response. */ - func testVerifyPhoneNumberUIDelegateUnstructuredError() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateUnstructuredError() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringUnstructuredError, errorCode: AuthErrorCode.appVerificationUserInteractionFailure.rawValue, function: #function, @@ -214,10 +403,10 @@ // The test runs correctly, but it's not clear how to automate fatal_error testing. Switching to // Swift exceptions would break the API. /** @fn testVerifyPhoneNumberUIDelegateRaiseException - @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an - exception. + @brief Tests a invocation of @c verifyPhoneNumber:UIDelegate:completion: which results in an + exception. */ - func SKIPtestVerifyPhoneNumberUIDelegateRaiseException() throws { + func SKIPtestVerifyPhoneNumberUIDelegateRaiseException() async throws { initApp(#function) let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) auth.mainBundleUrlTypes = [["CFBundleURLSchemes": ["fail"]]] @@ -228,11 +417,11 @@ } /** @fn testNotForwardingNotification - @brief Tests returning an error for the app failing to forward notification. + @brief Tests returning an error for the app failing to forward notification. */ func testNotForwardingNotification() throws { - func testVerifyPhoneNumberUIDelegateUnstructuredError() throws { - try internalTestVerify( + func testVerifyPhoneNumberUIDelegateUnstructuredError() async throws { + try await internalTestVerify( errorURLString: PhoneAuthProviderTests.kFakeRedirectURLStringUnstructuredError, errorCode: AuthErrorCode.appVerificationUserInteractionFailure.rawValue, function: #function, @@ -244,10 +433,10 @@ } /** @fn testMissingAPNSToken - @brief Tests returning an error for the app failing to provide an APNS device token. + @brief Tests returning an error for the app failing to provide an APNS device token. */ - func testMissingAPNSToken() throws { - try internalTestVerify( + func testMissingAPNSToken() async throws { + try await internalTestVerify( errorCode: AuthErrorCode.missingAppToken.rawValue, function: #function, useClientID: true, @@ -268,28 +457,28 @@ } /** @fn testVerifyClient - @brief Tests verifying client before sending verification code. + @brief Tests verifying client before sending verification code. */ func testVerifyClient() throws { try internalFlow(function: #function, useClientID: true, reCAPTCHAfallback: false) } /** @fn testSendVerificationCodeFailedRetry - @brief Tests failed retry after failing to send verification code. + @brief Tests failed retry after failing to send verification code. */ func testSendVerificationCodeFailedRetry() throws { try internalFlowRetry(function: #function) } /** @fn testSendVerificationCodeSuccessfulRetry - @brief Tests successful retry after failing to send verification code. + @brief Tests successful retry after failing to send verification code. */ func testSendVerificationCodeSuccessfulRetry() throws { try internalFlowRetry(function: #function, goodRetry: true) } /** @fn testPhoneAuthCredentialCoding - @brief Tests successful archiving and unarchiving of @c PhoneAuthCredential. + @brief Tests successful archiving and unarchiving of @c PhoneAuthCredential. */ func testPhoneAuthCredentialCoding() throws { let kVerificationID = "My verificationID" @@ -315,7 +504,7 @@ } /** @fn testPhoneAuthCredentialCodingPhone - @brief Tests successful archiving and unarchiving of @c PhoneAuthCredential after other constructor. + @brief Tests successful archiving and unarchiving of @c PhoneAuthCredential after other constructor. */ func testPhoneAuthCredentialCodingPhone() throws { let kTemporaryProof = "Proof" @@ -340,6 +529,27 @@ XCTAssertEqual(unarchivedCredential.provider, PhoneAuthProvider.id) } + private func testRecaptchaFlowError(function: String, rceError: Error) async throws { + initApp(function) + let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) + // TODO: Figure out how to mock objective C's FIRRecaptchaGetToken response + // Mocking the output of verify() method + let provider = PhoneAuthProvider.provider(auth: auth) + let mockVerifier = FakeAuthRecaptchaVerifier(error: rceError) + AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) + rpcIssuer.rceMode = "ENFORCE" + do { + let _ = try await provider.verifyClAndSendVerificationCodeWithRecaptcha( + toPhoneNumber: kTestPhoneNumber, + retryOnInvalidAppCredential: false, + uiDelegate: nil, + recaptchaVerifier: mockVerifier + ) + } catch { + XCTAssertEqual((error as NSError).code, (rceError as NSError).code) + } + } + private func internalFlowRetry(function: String, goodRetry: Bool = false) throws { let function = function initApp(function, useClientID: true, fakeToken: true) @@ -536,7 +746,6 @@ /** @fn testVerifyClient @brief Tests verifying client before sending verification code. */ - private func internalTestVerify(errorString: String? = nil, errorURLString: String? = nil, errorCode: Int = 0, @@ -546,13 +755,13 @@ bothClientAndAppID: Bool = false, reCAPTCHAfallback: Bool = false, forwardingNotification: Bool = true, - presenterError: Error? = nil) throws { + presenterError: Error? = nil) async throws { initApp(function, useClientID: useClientID, bothClientAndAppID: bothClientAndAppID, testMode: testMode, forwardingNotification: forwardingNotification) let auth = try XCTUnwrap(PhoneAuthProviderTests.auth) let provider = PhoneAuthProvider.provider(auth: auth) - let expectation = self.expectation(description: function) + var expectations: [XCTestExpectation] = [] if !reCAPTCHAfallback { // Fake out appCredentialManager flow. @@ -560,7 +769,8 @@ secret: kTestSecret) } else { // 1. Intercept, handle, and test the projectConfiguration RPC calls. - let projectConfigExpectation = self.expectation(description: "projectConfiguration") + let projectConfigExpectation = expectation(description: "projectConfiguration") + expectations.append(projectConfigExpectation) rpcIssuer?.projectConfigRequester = { request in XCTAssertEqual(request.apiKey, PhoneAuthProviderTests.kFakeAPIKey) projectConfigExpectation.fulfill() @@ -575,9 +785,23 @@ } } } - + if reCAPTCHAfallback { + // Use fake authURLPresenter so we can test the parameters that get sent to it. + let urlString = errorURLString ?? + PhoneAuthProviderTests.kFakeRedirectURLStringWithReCAPTCHAToken + let errorTest = errorURLString != nil + PhoneAuthProviderTests.auth?.authURLPresenter = + FakePresenter( + urlString: urlString, + clientID: useClientID ? PhoneAuthProviderTests.kFakeClientID : nil, + firebaseAppID: useClientID ? nil : PhoneAuthProviderTests.kFakeFirebaseAppID, + errorTest: errorTest, + presenterError: presenterError + ) + } if errorURLString == nil, presenterError == nil { - let requestExpectation = self.expectation(description: "verifyRequester") + let requestExpectation = expectation(description: "verifyRequester") + expectations.append(requestExpectation) rpcIssuer?.verifyRequester = { request in XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) switch request.codeIdentity { @@ -605,38 +829,22 @@ } } } - if reCAPTCHAfallback { - // Use fake authURLPresenter so we can test the parameters that get sent to it. - let urlString = errorURLString ?? - PhoneAuthProviderTests.kFakeRedirectURLStringWithReCAPTCHAToken - let errorTest = errorURLString != nil - PhoneAuthProviderTests.auth?.authURLPresenter = - FakePresenter( - urlString: urlString, - clientID: useClientID ? PhoneAuthProviderTests.kFakeClientID : nil, - firebaseAppID: useClientID ? nil : PhoneAuthProviderTests.kFakeFirebaseAppID, - errorTest: errorTest, - presenterError: presenterError - ) - } let uiDelegate = reCAPTCHAfallback ? FakeUIDelegate() : nil - // 2. After setting up the parameters, call `verifyPhoneNumber`. - provider - .verifyPhoneNumber(kTestPhoneNumber, uiDelegate: uiDelegate) { verificationID, error in - - // 8. After the response triggers the callback in the FakePresenter, verify the callback. - XCTAssertTrue(Thread.isMainThread) - if errorCode != 0 { - XCTAssertNil(verificationID) - XCTAssertEqual((error as? NSError)?.code, errorCode) - } else { - XCTAssertNil(error) - XCTAssertEqual(verificationID, self.kTestVerificationID) - } - expectation.fulfill() - } - waitForExpectations(timeout: 5) + do { + // Call the async function to verify the phone number + let verificationID = try await provider.verifyPhoneNumber( + kTestPhoneNumber, + uiDelegate: uiDelegate + ) + // Assert that the verificationID matches the expected value + XCTAssertEqual(verificationID, kTestVerificationID) + } catch { + // If an error occurs, assert that verificationID is nil and the error code matches the + // expected value + XCTAssertEqual((error as NSError).code, errorCode) + } + await fulfillment(of: expectations, timeout: 5.0) } private func initApp(_ functionName: String, @@ -689,6 +897,23 @@ } } + class FakeAuthRecaptchaVerifier: AuthRecaptchaVerifier, @unchecked Sendable { + var captchaResponse: String + var error: Error? + init(captchaResponse: String? = nil, error: Error? = nil) { + self.captchaResponse = captchaResponse ?? "NO_RECAPTCHA" + self.error = error + super.init() + } + + override func verify(forceRefresh: Bool, action: AuthRecaptchaAction) async throws -> String { + if let error = error { + throw error + } + return captchaResponse + } + } + class FakeTokenManager: AuthAPNSTokenManager { override func getTokenInternal(callback: @escaping (Result) -> Void) { let error = NSError(domain: "dummy domain", code: AuthErrorCode.missingAppToken.rawValue) diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index bb7a247fadf..8ff45d7d073 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -42,6 +42,7 @@ class RPCBaseTests: XCTestCase { let kCreationDateTimeIntervalInSeconds = 1_505_858_500.0 let kLastSignInDateTimeIntervalInSeconds = 1_505_858_583.0 let kTestPhoneNumber = "415-555-1234" + let kIdToken = "FAKE_ID_TOKEN" static let kOAuthSessionID = "sessionID" static let kOAuthRequestURI = "requestURI" let kGoogleIDToken = "GOOGLE_ID_TOKEN" diff --git a/FirebaseAuth/Tests/Unit/StartMFAEnrollmentRequestTests.swift b/FirebaseAuth/Tests/Unit/StartMFAEnrollmentRequestTests.swift index be39a361563..bde8558031a 100644 --- a/FirebaseAuth/Tests/Unit/StartMFAEnrollmentRequestTests.swift +++ b/FirebaseAuth/Tests/Unit/StartMFAEnrollmentRequestTests.swift @@ -23,6 +23,13 @@ import XCTest @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) class StartMFAEnrollmentRequestTests: RPCBaseTests { let kAPIKey = "APIKey" + let kIDToken = "idToken" + let kTOTPEnrollmentInfo = "totpEnrollmentInfo" + let kPhoneEnrollmentInfo = "enrollmentInfo" + let kPhoneNumber = "phoneNumber" + let kReCAPTCHAToken = "recaptchaToken" + let kCaptchaResponse = "captchaResponse" + let kRecaptchaVersion = "recaptchaVersion" /** @fn testTOTPStartMFAEnrollmentRequest @@ -58,4 +65,55 @@ class StartMFAEnrollmentRequestTests: RPCBaseTests { XCTAssertEqual(totpInfo, [:]) XCTAssertNil(requestDictionary[kPhoneEnrollmentInfo]) } + + /** + @fn testPhoneStartMFAEnrollmentRequest + @brief Tests the Start MFA Enrollment using SMS request. + */ + func testPhoneStartMFAEnrollmentInjectRecaptchaFields() async throws { + // created a base startMFAEnrollment Request + let testPhoneNumber = "1234567890" + let testRecaptchaToken = "RECAPTCHA_FAKE_TOKEN" + + let requestConfiguration = AuthRequestConfiguration(apiKey: kAPIKey, appID: "appID") + let smsEnrollmentInfo = AuthProtoStartMFAPhoneRequestInfo( + phoneNumber: testPhoneNumber, + codeIdentity: CodeIdentity.recaptcha(testRecaptchaToken) + ) + let request = StartMFAEnrollmentRequest(idToken: kIDToken, + enrollmentInfo: smsEnrollmentInfo, + requestConfiguration: requestConfiguration) + + // inject reCAPTCHA response + let testRecaptchaResponse = "RECAPTCHA_FAKE_RESPONSE" + let testRecaptchaVersion = "RECAPTCHA_FAKE_ENTERPRISE" + request.injectRecaptchaFields( + recaptchaResponse: testRecaptchaResponse, + recaptchaVersion: testRecaptchaVersion + ) + + let expectedURL = + "https://identitytoolkit.googleapis.com/v2/accounts/mfaEnrollment:start?key=\(kAPIKey)" + + do { + try await checkRequest( + request: request, + expected: expectedURL, + key: kIDToken, + value: kIDToken + ) + } catch { + // Ignore error from missing users array in fake JSON return. + return + } + + let requestDictionary = try XCTUnwrap(rpcIssuer.decodedRequest as? [String: AnyHashable]) + let smsInfo = try XCTUnwrap(requestDictionary["phoneEnrollmentInfo"] as? [String: String]) + XCTAssertEqual(smsInfo[kPhoneNumber], testPhoneNumber) + XCTAssertEqual(smsInfo[kReCAPTCHAToken], testRecaptchaToken) + XCTAssertEqual(smsInfo[kRecaptchaVersion], kRecaptchaVersion) + XCTAssertEqual(smsInfo[kCaptchaResponse], testRecaptchaResponse) + + XCTAssertNil(requestDictionary[kTOTPEnrollmentInfo]) + } } diff --git a/FirebaseAuth/Tests/Unit/StartMFASignInRequestTests.swift b/FirebaseAuth/Tests/Unit/StartMFASignInRequestTests.swift new file mode 100644 index 00000000000..837273c403a --- /dev/null +++ b/FirebaseAuth/Tests/Unit/StartMFASignInRequestTests.swift @@ -0,0 +1,89 @@ +// Copyright 2024 Google LLC +// +// 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 XCTest + +@testable import FirebaseAuth + +/** @class StartMFASignInRequestTests + @brief Tests for @c StartMFASignInRequest + */ +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class StartMFASignInRequestTests: RPCBaseTests { + let kAPIKey = "APIKey" + let kMfaEnrollmentId = "mfaEnrollmentId" + let kTOTPEnrollmentInfo = "totpEnrollmentInfo" + let kPhoneEnrollmentInfo = "enrollmentInfo" + let kPhoneNumber = "phoneNumber" + let kReCAPTCHAToken = "recaptchaToken" + let kCaptchaResponse = "captchaResponse" + let kRecaptchaVersion = "recaptchaVersion" + + /** + @fn testPhoneStartMFASignInRequest + @brief Tests the Start MFA Sign In using SMS request. + */ + func testPhoneStartMFASignInRequest() async throws { + let testPendingCredential = "FAKE_PENDING_CREDENTIAL" + let testEnrollmentID = "FAKE_ENROLLMENT_ID" + let testPhoneNumber = "1234567890" + let testRecaptchaToken = "RECAPTCHA_FAKE_TOKEN" + + let requestConfiguration = AuthRequestConfiguration(apiKey: kAPIKey, appID: "appID") + let smsSignInInfo = AuthProtoStartMFAPhoneRequestInfo( + phoneNumber: testPhoneNumber, + codeIdentity: CodeIdentity.recaptcha(testRecaptchaToken) + ) + + let request = StartMFASignInRequest( + MFAPendingCredential: testPendingCredential, + MFAEnrollmentID: testEnrollmentID, + signInInfo: smsSignInInfo, + requestConfiguration: requestConfiguration + ) + + let expectedURL = + "https://identitytoolkit.googleapis.com/v2/accounts/mfaSignIn:start?key=\(kAPIKey)" + + // inject reCAPTCHA response + let testRecaptchaResponse = "RECAPTCHA_FAKE_RESPONSE" + let testRecaptchaVersion = "RECAPTCHA_FAKE_ENTERPRISE" + request.injectRecaptchaFields( + recaptchaResponse: testRecaptchaResponse, + recaptchaVersion: testRecaptchaVersion + ) + + do { + try await checkRequest( + request: request, + expected: expectedURL, + key: kMfaEnrollmentId, + value: testEnrollmentID + ) + } catch { + // Ignore error from missing users array in fake JSON return. + return + } + + let requestDictionary = try XCTUnwrap(rpcIssuer.decodedRequest as? [String: AnyHashable]) + let smsInfo = try XCTUnwrap(requestDictionary["phoneEnrollmentInfo"] as? [String: String]) + XCTAssertEqual(smsInfo[kPhoneNumber], testPhoneNumber) + XCTAssertEqual(smsInfo[kReCAPTCHAToken], testRecaptchaToken) + XCTAssertEqual(smsInfo[kRecaptchaVersion], kRecaptchaVersion) + XCTAssertEqual(smsInfo[kCaptchaResponse], testRecaptchaResponse) + + XCTAssertNil(requestDictionary[kTOTPEnrollmentInfo]) + } +} From 2176e99cc68856131241e584c1a1f22668c846e3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:58:23 -0500 Subject: [PATCH 66/98] [Auth] Undo unchecked Sendable addition (#14168) --- .../Sources/Swift/Utilities/AuthRecaptchaVerifier.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index 7fd2c8c092c..4bf7346c683 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -67,7 +67,7 @@ } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) - class AuthRecaptchaVerifier: @unchecked Sendable { + class AuthRecaptchaVerifier { private(set) weak var auth: Auth? private(set) var agentConfig: AuthRecaptchaConfig? private(set) var tenantConfigs: [String: AuthRecaptchaConfig] = [:] From a2f04f440614acf9ff26b7cf908298c033f6f7ba Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 27 Nov 2024 16:18:45 -0800 Subject: [PATCH 67/98] Update Firestore binary for 11.6.0 (#14184) --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 73151c6c226..f0a2bf958c4 100644 --- a/Package.swift +++ b/Package.swift @@ -1505,8 +1505,8 @@ func firestoreTargets() -> [Target] { } else { return .binaryTarget( name: "FirebaseFirestoreInternal", - url: "https://dl.google.com/firebase/ios/bin/firestore/11.5.0/rc0/FirebaseFirestoreInternal.zip", - checksum: "32df6c2cfce97249ad4c333bade9af5c2301a2b35c285980355320a3398d5aef" + url: "https://dl.google.com/firebase/ios/bin/firestore/11.6.0/rc0/FirebaseFirestoreInternal.zip", + checksum: "ad9d6cf31120ba0a91dbb9ccbe7ad08276a88565f6c79216929ec93a7d436459" ) } }() From 2e02253fd1ce99145bcbf1bb367ccf61bd0ca46b Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 27 Nov 2024 19:49:20 -0500 Subject: [PATCH 68/98] [Auth] Add default values for decoding nil properties in UserInfoImpl (#14185) --- FirebaseAuth/CHANGELOG.md | 8 +++++++- .../Sources/Swift/User/UserInfoImpl.swift | 17 ++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index c91a44333f6..fd141940888 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -5,7 +5,13 @@ `Auth.currentUser` API. This resolves some Firebase 11 issues where the current user is unexpectedly `nil` at startup. - [fixed] Restore Firebase 10 decoding behavior to prevent user provider data - from being decoded as `nil`. (#14011) + from always being decoded as `nil` . Note that this fix was only needed for + cases where Firebase 11 was reading data written by Firebase 10. (#14011) +- [fixed] Restore Firebase 10 decoding behavior to prevent user provider data + from being decoded as `nil` when a user has multiple linked providers. Note + that this fix was only needed for cases where Firebase 11 was reading data + written by Firebase 10. Note that this fix will not be in the 11.6.0 zip and + Carthage distributions, but will be included from 11.6.0 onwards. (#14011) # 11.5.0 - [fixed] Restore pre-Firebase 11 decoding behavior to prevent users getting diff --git a/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift b/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift index 23ef4c8de9a..8d3b96d0e43 100644 --- a/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift +++ b/FirebaseAuth/Sources/Swift/User/UserInfoImpl.swift @@ -88,17 +88,16 @@ class UserInfoImpl: NSObject, UserInfo { } required convenience init?(coder: NSCoder) { - guard let providerID = coder.decodeObject( + let providerID = coder.decodeObject( of: [NSString.self], forKey: UserInfoImpl.kProviderIDCodingKey - ) as? String, - let userID = coder.decodeObject( - of: [NSString.self], - forKey: UserInfoImpl.kUserIDCodingKey - ) as? String - else { - return nil - } + ) as? String ?? "" + // Not all providers have a corresponding user ID (e.g. phone auth), so + // fall back to an empty string. + let userID = coder.decodeObject( + of: [NSString.self], + forKey: UserInfoImpl.kUserIDCodingKey + ) as? String ?? "" let displayName = coder.decodeObject( of: [NSString.self], forKey: UserInfoImpl.kDisplayNameCodingKey From 1d367ae7504b08580852711bacae3203b657ef0b Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 27 Nov 2024 20:37:26 -0500 Subject: [PATCH 69/98] [Infra] Update GSI test account refresh token (#14187) --- .../AuthSample/Credentials.swift.gpg | Bin 1596 -> 1594 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/scripts/gha-encrypted/AuthSample/Credentials.swift.gpg b/scripts/gha-encrypted/AuthSample/Credentials.swift.gpg index bf9242c8e6874a89703cc6a51bd82bc9a494b3ce..1e24d1cc1fdc9fbef50997371dba1202dad06e08 100644 GIT binary patch literal 1594 zcmV-A2F3Y|4Fm}T2#`GfWp(Q(o z&6*&8zQrG9V*n~jCqJ@oaueW&K+aXk$soZEYorh}5^Mf(6AoD18)yNVtM_zZZx!ju zbC7OQ+xl39>zy~6qfCOxzK>PN06mJrqZuDAzOS;Qi;K#PS5RakQL2IK(u9RQp-S*y z^*2>*=z@<)%KTG`d{|O=*%Je@wuKmXWJX@4fPWoRx@NHiNu1_eB3Nc+Z-W}s`)t80 zH(h~FoVkm5S~CKC6cfz0dY;YWHRv^2yF$ICk>NQ3M(3%sF~*qcvy{>^xo;fkK^R-t zKP*_^*p)<1)ffa7^Nz#!J?e3Ij`%44ne{Aqu;KV^;mj8ceIO)*kt$02}}n6qVD^^f7zz0uSdnuOc6F<`>ewHL9z%p>mcxy-ACC65_cIh4!{!Y1eSz>+LjtEpbB+yaA z$AN(WFCc?p45Zf%PtGrHw5vhm#Qf&M*@M$78B=gunf-`>))!!ldYd=JLhRXPM5}Hm zuM1?kwRQv)LcW#hUKXFwjDk2;-XokO^Auo77YlbOG`>@_dfdu=?%>#IZo}-p+es=^ zx7hm-b?bqtAsd}p#ViOgd~vft;X~-!94_HQ*`1s^q8(;nBT`#QPy=J}#5sh08p&C! zYO<(l)=k;PN}*FWt%C$`SHY?*#2k6~!At=L@(dsHd&5~&kW=bnkI&O77Tg@zfZB#+ zDggZxuxR_^4?;$ZaGGjgE`|=Al>k8olrV%2JsF9#&mvDdXwC@gr9y z1cOBb4#-q2-kXEwtRgxYudSVA7QSoS@OMW8=oA|5^_|)Y@mz*AnF$6@^rX-02nwx# zrUdB?Dhyq?Q?+v?10~us@sEojZE}UnZwC7ZgOTS#e--9V$P(y3NBnspxSeHRwK#^E zv^R9R`m1b9*p7k&%$TW$A>is)F*>uRF<>%8%x^hEKkkA(^D_XZE6 zS<$MhS9);G=>Sjgp@?ydybpL^rt1Xo5>_Kd(swcqU4H7NmK%Oc>YjX6znqq=Z{sYV zX+Wt`AB-UOa@>4iD3^=ZvXP)N0X&jAbtI-ag=1I^ltdxhi_+29CqE3h;Jz9 z^#Dc?hPGJZHGM~0OE@f(U}LQitkI%RcjT6y-OSnxZjZK`UOb<>9D zQ8j!Zoe9~?%c3$GXUzOX(Bw{%-cc$HE7M)^>xP#u_o4F&@u4>5;#{D#A(ioA49%j` z#dav`IlQ=NKa3jAwPyvwka9Rk6Gj zvf?pqX!Yy0O_l!;EkCNo3k;MC9qN4wKc&Gy|f^E%X%RMqa8>`>3^!ym?DE6JXm^dL41ONa4 literal 1596 zcmV-C2E+M`4Fm}T2zGh_N@-=u_y5xB0kA@Y3iE4K&&Wd_B-{~Le4i@MT!u;57=dW= zL7RblL%U>uqAXDX2)vot5KnEQkf;`Wr%mY}^Ao&Jp!^q~P)niN{w>aO70q&&4S!@b!{h*OMjM}Gsk zG0JW&Yi!pxThET9=K79t1y0R$IS)5;2`-GW3jef>Od~h`-w<8$q?rbt^rQ3uH7mr| z#DQWg33inE{@Bj_e_l>sS)?eu9nsB-^)7 zxFno3@3AI<+qaz^)^3fz*153*wEVf=W-`xHjP8LA?OExn%nHmRPGkjj>uq0mEQNv) zouNoOGV8#Whxt%hjTa6cUx{inohjrmZiUJXZ}@A3gKF;P7Lpn&K@+C08f*$>Ut2k; zEs(CJ=gR#bOVOD^I9HS|0hL|=eJE6vUhC%xY|Hzp&D^Qgmn%0Byzsxi#8 z6CDK)E~9G*xP2#t_zc?*d;#$+-4My(;PT`t>wI(M>hFCuI7|pi+(MC5&oLU#delgL zJ+r%HmSPx_{_Bh%85(}j7v+x3TS>z#L0OCkmQ2!-HLg=Uo^)T*(_7|r+#pkshiJA+ z5l=<%vq)q7)Z;fTSK&ORnfi36(3WnRp1Z_i^!x>+E-$UW3&hi^bzYmM>HwqhS?4SJD>e|oL0@PDkX$-9a2rlBA?*7K)4y>U_0 z)EnZC{@n4tRW+ME}8qf1BJ^a*Q*9KXRQ&X;wP*xD^<;J z{5B0Qhdyya;b9NX9GIRu$#)5prKBBS+PCYk%e?%Ga}M!66%CxJe5_OsL!<4bB6_S7LZ?gWWK>5v z_^czGU6piDL(+2WYInxNeQfX~lL@L@Sja?&^Nh)bfJN{S`Emk}ZP#%3yx6Sz$-DUj z+qZ^~smDf3aAwt&v-8l(qPpv+LJy{{=R$bV$w22`K{1{dsH`$=4NbLwz@mKB&omc9 z4C8v05cH^fHG}Nv(Ia`(&uPV})W{(HqM7(#VA^LQsyuwO4I1UiAbA^~<7Fk5T)!1J zO1d#M1h6a>J;e&GK8BoR?IML0qB+ktm}s4cm!3gT%$t;oYLRLW1Q*|Dp{L}Jsf@;+ zE*MiOg(wD~dtcMQ;~Wq2jYO)Jq$bFK0xtSWTt{A!wqx^&sDS&jdSQ&K*|&rIGGQyQ z*6H_;vE}a@bv1UUVGrI!b#Uo{Mse<2-)o`QA3r&Pl7|;xi{;`Fk2ok^m+_V8K)W(Y zEd~wK==Nt=c8h(^(N}K*$KP$BO$>tnSQ Date: Tue, 3 Dec 2024 11:03:14 -0500 Subject: [PATCH 70/98] [Infra] Follow-up to #14176 (#14177) --- .github/workflows/firestore.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index ab5c94a6303..065d0b365cc 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -30,9 +30,9 @@ jobs: # Only when this is not a scheduled run if: github.event_name != 'schedule' outputs: - changed: ${{ steps.firestore_src_changes.outputs.sources || steps.related_changes.outputs.other_changes }} + changed: ${{ steps.firestore_src_changes.outputs.sources == 'true' || steps.related_changes.outputs.other_changes == 'true' }} steps: - - uses: dorny/paths-filter@v2 + - uses: dorny/paths-filter@v3.0.2 id: firestore_src_changes with: predicate-quantifier: 'every' @@ -40,8 +40,8 @@ jobs: sources: # Firestore sources - 'Firestore/**' - - '!**/*.md' - - uses: dorny/paths-filter@v2 + - '!Firestore/**/*.md' + - uses: dorny/paths-filter@v3.0.2 id: related_changes with: filters: | From 44a8b5dbf5a33814661bb54ed7a2a491c17e2d43 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 3 Dec 2024 08:44:43 -0800 Subject: [PATCH 71/98] Carthage 11.6.0 (#14204) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + .../FirebaseAnalyticsOnDeviceConversionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json | 3 ++- 20 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index b43f6d31b8d..19a6439748f 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseABTesting-2233510ff87da3b6.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseABTesting-4d0b187af6fd8d67.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseABTesting-0c318b2c019b4484.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseABTesting-b416850a88a115fd.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/ABTesting-d0fdf10c43e985b1.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/ABTesting-d0fdf10c43e985b1.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/ABTesting-a71d17cadc209af9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json index 892b10e4152..2001e0b74d9 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAdMobBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/Google-Mobile-Ads-SDK-80ba4cb995505158.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/Google-Mobile-Ads-SDK-3df614a58e6a5fa6.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/Google-Mobile-Ads-SDK-34abc42769a452ec.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/Google-Mobile-Ads-SDK-ae940d9c2e982d0c.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/AdMob-8a654a42c33bbcc8.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/AdMob-63dab3b525b94cd9.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/AdMob-134752c6180a2a41.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index 6eef13dc1a5..bd4faf3b28a 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalytics-fd2c71a90d62b88a.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalytics-525b465eb296d09e.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAnalytics-7302159af7baa5d6.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseAnalytics-2e55879349ec4350.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Analytics-2468c231ebeb7922.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Analytics-bc8101d420b896c5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Analytics-d2b6a6b0242db786.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json index c1494a9cf81..bae98a357d4 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsOnDeviceConversionBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAnalyticsOnDeviceConversion-918bc6e0b7a2fd94.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAnalyticsOnDeviceConversion-1640c514418a23da.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAnalyticsOnDeviceConversion-8f2f37c75bba22f1.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseAnalyticsOnDeviceConversion-b8b1ff77c9cef93f.zip", "9.0.0": "https://dl.google.com/dl/firebase/ios/carthage/9.0.0/FirebaseAnalyticsOnDeviceConversion-31aedde70a736b8a.zip", "9.1.0": "https://dl.google.com/dl/firebase/ios/carthage/9.1.0/FirebaseAnalyticsOnDeviceConversion-f13b5a47d1e3978d.zip", "9.2.0": "https://dl.google.com/dl/firebase/ios/carthage/9.2.0/FirebaseAnalyticsOnDeviceConversion-2ebf567c4d97de12.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index ef662dff5d2..92c52101330 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppCheck-89c39bdcf0bb90fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppCheck-9b0c4a9489968b07.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAppCheck-8b9bb98738bf8bcf.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseAppCheck-b667b2d77859e6f5.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseAppCheck-9ef1d217cf057203.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseAppCheck-fc03215d9fe45d3a.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseAppCheck-6ebe9e9539f06003.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index 6610d08d71d..b3bb449751c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAppDistribution-6d2eccaccfd3145f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAppDistribution-20ac94ca344af731.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAppDistribution-6d2e83d234fea209.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseAppDistribution-fa8b697f72858bab.zip", "6.31.0": "https://dl.google.com/dl/firebase/ios/carthage/6.31.0/FirebaseAppDistribution-07f6a2cf7f576a8a.zip", "6.32.0": "https://dl.google.com/dl/firebase/ios/carthage/6.32.0/FirebaseAppDistribution-a9c4f5db794508ca.zip", "6.33.0": "https://dl.google.com/dl/firebase/ios/carthage/6.33.0/FirebaseAppDistribution-448a96d2ade54581.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 4b42255a58b..0a8772e6ab0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseAuth-93dd2965b3f79b98.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseAuth-5faf6dc3bb16c732.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseAuth-0c8317aa5649f10f.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseAuth-64df854207604748.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Auth-0fa76ba0f7956220.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Auth-5ddd2b4351012c7a.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Auth-5e248984d78d7284.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index e1e7795e6e5..26283243a1f 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseCrashlytics-282a6f3cf3445787.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseCrashlytics-d5c125d6416f6e0a.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseCrashlytics-8b3c9a29b8afd9b3.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseCrashlytics-b760ff3d3f7fa48d.zip", "6.15.0": "https://dl.google.com/dl/firebase/ios/carthage/6.15.0/FirebaseCrashlytics-1c6d22d5b73c84fd.zip", "6.16.0": "https://dl.google.com/dl/firebase/ios/carthage/6.16.0/FirebaseCrashlytics-938e5fd0e2eab3b3.zip", "6.17.0": "https://dl.google.com/dl/firebase/ios/carthage/6.17.0/FirebaseCrashlytics-fa09f0c8f31ed5d9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 6e0f6983421..a60f1571f78 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDatabase-38634b55050b94fe.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDatabase-ed125984da534e96.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseDatabase-c31e803cad22c253.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseDatabase-9d2f09f945978fe0.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Database-1f7a820452722c7d.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Database-1f7a820452722c7d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Database-59a12d87456b3e1c.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json index c4c50f91f6e..c1ed80bda46 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDynamicLinksBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseDynamicLinks-95f7e222d8456304.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseDynamicLinks-f3f9d6cc60c8b832.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseDynamicLinks-2d21fc8dc1ab3b10.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseDynamicLinks-7668e8c844ee2916.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/DynamicLinks-6a76740211df73f5.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/DynamicLinks-6a76740211df73f5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/DynamicLinks-6a76740211df73f5.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index 45a14e7f6e6..dbb927cfb59 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFirestore-e1283f8cd2e0f3ec.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFirestore-f5864e67ddbbc9e8.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseFirestore-7cf86f9ac9b3545c.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseFirestore-01f9c373d4a1aad6.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Firestore-68fc02c229d0cc69.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Firestore-87a804ab561d91db.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Firestore-ecb3eea7bde7e8e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index efd2f26058d..4f8d2b3e8e4 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseFunctions-02693a7583303912.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseFunctions-8fce8623ed1c6b86.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseFunctions-367ecac87d727ede.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseFunctions-6f8db76aa21e01a3.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Functions-f4c426016dd41e38.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Functions-c6c44427c3034736.zip", "5.0.0": "https://dl.google.com/dl/firebase/ios/carthage/5.0.0/Functions-146f34c401bd459b.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index e8fd8e45d64..e810e43b9fe 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/GoogleSignIn-8ce1c31ca2236212.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/GoogleSignIn-59eb371d148a2e3a.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/GoogleSignIn-f7dcc2bce87fcb30.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/GoogleSignIn-aabe9743448ca661.zip", "6.0.0": "https://dl.google.com/dl/firebase/ios/carthage/6.0.0/GoogleSignIn-de9c5d5e8eb6d6ea.zip", "6.1.0": "https://dl.google.com/dl/firebase/ios/carthage/6.1.0/GoogleSignIn-8c82f2870573a793.zip", "6.10.0": "https://dl.google.com/dl/firebase/ios/carthage/6.10.0/GoogleSignIn-ff3aef61c4a55b05.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index 13d04a0e6ea..71f88045e60 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseInAppMessaging-3a1a331c86520356.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseInAppMessaging-a8054099dd2918b3.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseInAppMessaging-1264f987e42294c5.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseInAppMessaging-912c056e69fd1a60.zip", "5.10.0": "https://dl.google.com/dl/firebase/ios/carthage/5.10.0/InAppMessaging-a7a3f933362f6e95.zip", "5.11.0": "https://dl.google.com/dl/firebase/ios/carthage/5.11.0/InAppMessaging-fa28ce1b88fbca93.zip", "5.12.0": "https://dl.google.com/dl/firebase/ios/carthage/5.12.0/InAppMessaging-fa28ce1b88fbca93.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 93b98c740cd..067b7bb67f5 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMLModelDownloader-517f51af92733a7f.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMLModelDownloader-069609cbcde7e789.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseMLModelDownloader-c6340805afa15d66.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseMLModelDownloader-a91e9e37024a3f32.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseMLModelDownloader-8f972757fb181320.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseMLModelDownloader-058ad59fa6dc0111.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseMLModelDownloader-286479a966d2fb37.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 02aa108e989..1c530104cfd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseMessaging-8a39834fead3c581.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseMessaging-2d09725e8b98d199.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseMessaging-984ae5d3101abc86.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseMessaging-6b71a5b258ab61db.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Messaging-a22ef2b5f2f30f82.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Messaging-94fa4e090c7e9185.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Messaging-2a00a1c64a19d176.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index ed98e7ed341..8e8802efb89 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebasePerformance-a489ac7a27d9b53d.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebasePerformance-9a6f62e80c2324f4.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebasePerformance-28996619a5fdc4b7.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebasePerformance-9cbd51ad69fbfb15.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Performance-d8693eb892bfa05b.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Performance-0a400f9460f7a71d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Performance-f5b4002ab96523e4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index e00f9946e4d..d850ee652da 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseRemoteConfig-940ed38696414882.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseRemoteConfig-ec432e976582d0eb.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseRemoteConfig-672acb139b4848ef.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseRemoteConfig-d60da8df32c1796b.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/RemoteConfig-7e9635365ccd4a17.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/RemoteConfig-e7928fcb6311c439.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/RemoteConfig-9ab1ca5f360a1780.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index b5a9246e76e..946d31dbe3c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -34,6 +34,7 @@ "11.3.0": "https://dl.google.com/dl/firebase/ios/carthage/11.3.0/FirebaseStorage-0435eeaa87324cd4.zip", "11.4.0": "https://dl.google.com/dl/firebase/ios/carthage/11.4.0/FirebaseStorage-0b7a2306152984a2.zip", "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseStorage-a1f0f159f3d7072b.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseStorage-1826dbf39f492220.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Storage-6b3e77e1a7fdbc61.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Storage-4721c35d2b90a569.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Storage-821299369b9d0fb2.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json index 6f3fcd57470..5964ddede7e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseVertexAIBinary.json @@ -1,3 +1,4 @@ { - "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip" + "11.5.0": "https://dl.google.com/dl/firebase/ios/carthage/11.5.0/FirebaseVertexAI-d5d0ffd8010245da.zip", + "11.6.0": "https://dl.google.com/dl/firebase/ios/carthage/11.6.0/FirebaseVertexAI-6f6520d750ba54c4.zip" } From a676158e0e29e99e00be8b12db5b5b5b781afc7f Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 3 Dec 2024 12:48:31 -0800 Subject: [PATCH 72/98] Update versions for Release 11.7.0 (#14206) --- Firebase.podspec | 48 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAnalytics.podspec | 8 ++-- FirebaseAnalyticsOnDeviceConversion.podspec | 4 +- FirebaseAppCheck.podspec | 4 +- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 4 +- FirebaseAuth.podspec | 6 +-- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 4 +- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 4 +- FirebaseDatabase.podspec | 4 +- FirebaseDynamicLinks.podspec | 4 +- FirebaseFirestore.podspec | 8 ++-- FirebaseFirestoreInternal.podspec | 4 +- FirebaseFunctions.podspec | 6 +-- FirebaseInAppMessaging.podspec | 4 +- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 6 +-- FirebaseMessaging.podspec | 4 +- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 4 +- FirebaseRemoteConfig.podspec | 4 +- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 6 +-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 6 +-- FirebaseVertexAI.podspec | 6 +-- GoogleAppMeasurement.podspec | 4 +- ...leAppMeasurementOnDeviceConversion.podspec | 2 +- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 35 files changed, 93 insertions(+), 93 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index c014f07db07..a3d8e68b54e 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 11.6.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 11.6.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 11.6.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 11.7.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 11.7.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 11.7.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 11.6.0' + ss.dependency 'FirebaseCore', '~> 11.7.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -79,13 +79,13 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' - ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.6.0' + ss.dependency 'FirebaseAnalytics/WithoutAdIdSupport', '~> 11.7.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 11.6.0' + ss.dependency 'FirebaseABTesting', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -95,13 +95,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 11.6.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 11.7.0-beta' ss.ios.deployment_target = '13.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 11.6.0' + ss.dependency 'FirebaseAppCheck', '~> 11.7.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -110,7 +110,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 11.6.0' + ss.dependency 'FirebaseAuth', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -120,7 +120,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 11.6.0' + ss.dependency 'FirebaseCrashlytics', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '12.0' ss.osx.deployment_target = '10.15' @@ -130,7 +130,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 11.6.0' + ss.dependency 'FirebaseDatabase', '~> 11.7.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -140,13 +140,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'DynamicLinks' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.6.0' + ss.ios.dependency 'FirebaseDynamicLinks', '~> 11.7.0' ss.ios.deployment_target = '13.0' end s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 11.6.0' + ss.dependency 'FirebaseFirestore', '~> 11.7.0' ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '13.0' @@ -154,7 +154,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 11.6.0' + ss.dependency 'FirebaseFunctions', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -164,20 +164,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.6.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.6.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 11.7.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 11.7.0-beta' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 11.6.0' + ss.dependency 'FirebaseInstallations', '~> 11.7.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 11.6.0' + ss.dependency 'FirebaseMessaging', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -187,7 +187,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 11.6.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 11.7.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -197,15 +197,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 11.6.0' - ss.tvos.dependency 'FirebasePerformance', '~> 11.6.0' + ss.ios.dependency 'FirebasePerformance', '~> 11.7.0' + ss.tvos.dependency 'FirebasePerformance', '~> 11.7.0' ss.ios.deployment_target = '13.0' ss.tvos.deployment_target = '13.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 11.6.0' + ss.dependency 'FirebaseRemoteConfig', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' @@ -215,7 +215,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 11.6.0' + ss.dependency 'FirebaseStorage', '~> 11.7.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '13.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index 76a3c6eacc6..6ff0c3dfcf4 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -52,7 +52,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 9e109930a87..08f55c44cf6 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.0' @@ -37,12 +37,12 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement', '11.6.0' + ss.dependency 'GoogleAppMeasurement', '11.7.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'WithoutAdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.6.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.7.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAnalyticsOnDeviceConversion.podspec b/FirebaseAnalyticsOnDeviceConversion.podspec index 4d57ab96f1b..8d0bc38fbf8 100644 --- a/FirebaseAnalyticsOnDeviceConversion.podspec +++ b/FirebaseAnalyticsOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalyticsOnDeviceConversion' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'On device conversion measurement plugin for FirebaseAnalytics. Not intended for direct use.' s.description = <<-DESC @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.cocoapods_version = '>= 1.12.0' - s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.6.0' + s.dependency 'GoogleAppMeasurementOnDeviceConversion', '11.7.0' s.static_framework = true diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 7f8995ac47c..fb70ab42001 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -46,7 +46,7 @@ Pod::Spec.new do |s| s.dependency 'AppCheckCore', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index fe888c5a945..4648898acb3 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 647a88b941c..7990568c824 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '11.6.0-beta' + s.version = '11.7.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,7 +30,7 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' s.dependency 'FirebaseInstallations', '~> 11.0' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index bdb9ee26263..0e9c9c3e641 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -58,8 +58,8 @@ supports email and password accounts, as well as several 3rd party authenticatio s.ios.framework = 'SafariServices' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index 872de49ce94..8d99dbe23ce 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index 877521ac9a4..cb3cedf4512 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,7 +51,7 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseAuth', '~> 11.0' s.dependency 'FirebaseFunctions', '~> 11.0' s.dependency 'FirebaseFirestore', '~> 11.0' diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 0587b7c19e2..57317f3ae98 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/Logger', '~> 8.0' - s.dependency 'FirebaseCoreInternal', '~> 11.6.0' + s.dependency 'FirebaseCoreInternal', '~> 11.7.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index cbabe65f98d..ccf8657401c 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index 6cab3696090..f29b9b46a5b 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index fb0d09d97de..50851982c3c 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,7 +59,7 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' s.dependency 'FirebaseRemoteConfigInterop', '~> 11.0' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index f6120d4915e..84f42e4b22d 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -47,7 +47,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseDynamicLinks.podspec b/FirebaseDynamicLinks.podspec index dda7be4f589..311c14be840 100644 --- a/FirebaseDynamicLinks.podspec +++ b/FirebaseDynamicLinks.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDynamicLinks' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Dynamic Links' s.description = <<-DESC @@ -34,7 +34,7 @@ Firebase Dynamic Links are deep links that enhance user experience and increase } s.frameworks = 'QuartzCore' s.weak_framework = 'WebKit' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index 92f5e3924c8..2399a185509 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' - s.dependency 'FirebaseFirestoreInternal', '11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' + s.dependency 'FirebaseFirestoreInternal', '11.7.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 704b099c0a1..393e948c95e 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -93,7 +93,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, } s.dependency 'FirebaseAppCheckInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' abseil_version = '~> 1.20240116.1' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index e95980c98ee..fac17619d58 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,8 +35,8 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' s.dependency 'FirebaseMessagingInterop', '~> 11.0' diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 53fe204fde8..f8aa4df33d2 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '11.6.0-beta' + s.version = '11.7.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,7 +80,7 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 3476e780078..b38f8954e19 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 879282861a3..cc088c673e6 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '11.6.0-beta' + s.version = '11.7.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,8 +36,8 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.0' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 95ac97e6631..f23caa247f2 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -62,7 +62,7 @@ device, and it is completely free. s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' s.dependency 'FirebaseInstallations', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0' s.dependency 'GoogleUtilities/Reachability', '~> 8.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index b95739b71be..33011dd9098 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index c35aa20a3cc..f1746389daa 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -59,7 +59,7 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'FirebaseRemoteConfig', '~> 11.0' s.dependency 'FirebaseSessions', '~> 11.0' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 03eeb4bf80b..d9c7b90b6f9 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -52,7 +52,7 @@ app update. } s.dependency 'FirebaseABTesting', '~> 11.0' s.dependency 'FirebaseSharedSwift', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.0' diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 1e8a2078665..6c18a8d3f05 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index d54cf449d3c..a6654f3d7ad 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,8 +39,8 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.dependency 'FirebaseInstallations', '~> 11.0' s.dependency 'GoogleDataTransport', '~> 10.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index 287e3bef90c..0755b22f7cf 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 753a4b558c5..062f87034fa 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -39,8 +39,8 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas s.dependency 'FirebaseAppCheckInterop', '~> 11.0' s.dependency 'FirebaseAuthInterop', '~> 11.0' - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0' s.dependency 'GoogleUtilities/Environment', '~> 8.0' diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index fdfe4d0a3e1..1657e38f2e6 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseVertexAI' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Vertex AI in Firebase SDK' s.description = <<-DESC @@ -46,8 +46,8 @@ Firebase SDK. s.dependency 'FirebaseAppCheckInterop', '~> 11.4' s.dependency 'FirebaseAuthInterop', '~> 11.4' - s.dependency 'FirebaseCore', '~> 11.6.0' - s.dependency 'FirebaseCoreExtension', '~> 11.6.0' + s.dependency 'FirebaseCore', '~> 11.7.0' + s.dependency 'FirebaseCoreExtension', '~> 11.7.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseVertexAI/Tests/Unit/' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 25b05e666bc..14daa13841e 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.default_subspecs = 'AdIdSupport' s.subspec 'AdIdSupport' do |ss| - ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.6.0' + ss.dependency 'GoogleAppMeasurement/WithoutAdIdSupport', '11.7.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end diff --git a/GoogleAppMeasurementOnDeviceConversion.podspec b/GoogleAppMeasurementOnDeviceConversion.podspec index 5c9f9f8ca2c..2664f2f68b6 100644 --- a/GoogleAppMeasurementOnDeviceConversion.podspec +++ b/GoogleAppMeasurementOnDeviceConversion.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurementOnDeviceConversion' - s.version = '11.6.0' + s.version = '11.7.0' s.summary = <<-SUMMARY On device conversion measurement plugin for Google App Measurement. Not intended for direct use. diff --git a/Package.swift b/Package.swift index f0a2bf958c4..f7c9ac2c9e0 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ import class Foundation.ProcessInfo import PackageDescription -let firebaseVersion = "11.6.0" +let firebaseVersion = "11.7.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index bf28d99c158..4a9f7afc4ef 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "11.6.0", + version: "11.7.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From b9fff5783d54e35219122d44d24782fe846d2f4c Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 3 Dec 2024 13:43:40 -0800 Subject: [PATCH 73/98] Minimize Crashlytics flakes (#14207) --- .github/workflows/crashlytics.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index f24d0f63de5..303e095865a 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -32,8 +32,10 @@ jobs: build-env: - os: macos-14 xcode: Xcode_15.2 + tests: --skip-tests - os: macos-15 xcode: Xcode_16.1 + tests: "" runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -48,7 +50,7 @@ jobs: max_attempts: 3 retry_on: error retry_wait_seconds: 120 - command: scripts/pod_lib_lint.rb FirebaseCrashlytics.podspec --platforms=${{ matrix.target }} ${{ matrix.tests }} ${{ matrix.flags }} + command: scripts/pod_lib_lint.rb FirebaseCrashlytics.podspec --platforms=${{ matrix.target }} ${{ matrix.build-env.tests }} ${{ matrix.flags }} spm-package-resolved: From 454f3999ce8fd4d21f4b7e17c469c9b872c58741 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:58:52 -0500 Subject: [PATCH 74/98] [Auth] Use result type to wrap completion handlers internally (#13563) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 92 +++++++++---------- .../AuthProvider/PhoneAuthProvider.swift | 13 ++- .../SignIn/StartMFASignInResponse.swift | 2 +- .../RPC/SendVerificationTokenResponse.swift | 2 +- .../MultiFactor/MultiFactorResolver.swift | 2 +- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index b8abba0a933..27aeccf4ece 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -300,9 +300,9 @@ extension Auth: AuthInterop { Task { do { let response = try await self.backend.call(with: request) - Auth.wrapMainAsync(callback: completion, withParam: response.signinMethods, error: nil) + Auth.wrapMainAsync(callback: completion, with: .success(response.signinMethods)) } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Auth.wrapMainAsync(callback: completion, with: .failure(error)) } } } @@ -365,9 +365,9 @@ extension Auth: AuthInterop { withEmail: email, password: password ) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -463,9 +463,9 @@ extension Auth: AuthInterop { do { let authData = try await self.internalSignInAndRetrieveData(withCredential: credential, isReauthentication: false) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -544,9 +544,9 @@ extension Auth: AuthInterop { withCredential: credential, isReauthentication: false ) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -642,9 +642,9 @@ extension Auth: AuthInterop { do { let authData = try await self.internalSignInAndRetrieveData(withCredential: credential, isReauthentication: false) - decoratedCallback(authData, nil) + decoratedCallback(.success(authData)) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -710,7 +710,7 @@ extension Auth: AuthInterop { let decoratedCallback = self.signInFlowAuthDataResultCallback(byDecorating: completion) if let currentUser = self._currentUser, currentUser.isAnonymous { let result = AuthDataResult(withUser: currentUser, additionalUserInfo: nil) - decoratedCallback(result, nil) + decoratedCallback(.success(result)) return } let request = SignUpNewUserRequest(requestConfiguration: self.requestConfiguration) @@ -728,10 +728,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: true) - decoratedCallback(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -790,10 +791,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: response.isNewUser) - decoratedCallback(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -866,7 +868,7 @@ extension Auth: AuthInterop { action: AuthRecaptchaAction.signUpPassword) { response, error in if let error { DispatchQueue.main.async { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } return } @@ -881,7 +883,8 @@ extension Auth: AuthInterop { func internalCreateUserWithEmail(request: SignUpNewUserRequest, inResponse: SignUpNewUserResponse? = nil, - decoratedCallback: @escaping (AuthDataResult?, Error?) -> Void) { + decoratedCallback: @escaping (Result) + -> Void) { Task { do { var response: SignUpNewUserResponse @@ -900,11 +903,11 @@ extension Auth: AuthInterop { profile: nil, username: nil, isNewUser: true) - decoratedCallback(AuthDataResult(withUser: user, - additionalUserInfo: additionalUserInfo), - nil) + decoratedCallback( + .success(AuthDataResult(withUser: user, additionalUserInfo: additionalUserInfo)) + ) } catch { - decoratedCallback(nil, error) + decoratedCallback(.failure(error)) } } } @@ -1009,9 +1012,9 @@ extension Auth: AuthInterop { let actionCodeInfo = ActionCodeInfo(withOperation: operation, email: email, newEmail: response.verifiedEmail) - Auth.wrapMainAsync(callback: completion, withParam: actionCodeInfo, error: nil) + Auth.wrapMainAsync(callback: completion, with: .success(actionCodeInfo)) } catch { - Auth.wrapMainAsync(callback: completion, withParam: nil, error: error) + Auth.wrapMainAsync(callback: completion, with: .failure(error)) } } } @@ -2238,23 +2241,19 @@ extension Auth: AuthInterop { /// Invoked asynchronously on the main thread in the future. /// - Returns: Returns a block that updates the current user. func signInFlowAuthDataResultCallback(byDecorating callback: - ((AuthDataResult?, Error?) -> Void)?) -> (AuthDataResult?, Error?) -> Void { - let authDataCallback: (((AuthDataResult?, Error?) -> Void)?, AuthDataResult?, Error?) -> Void = - { callback, result, error in - Auth.wrapMainAsync(callback: callback, withParam: result, error: error) - } - return { authResult, error in - if let error { - authDataCallback(callback, nil, error) - return - } - do { - try self.updateCurrentUser(authResult?.user, byForce: false, savingToDisk: true) - } catch { - authDataCallback(callback, nil, error) - return + ((AuthDataResult?, Error?) -> Void)?) -> (Result) -> Void { + return { result in + switch result { + case let .success(authResult): + do { + try self.updateCurrentUser(authResult.user, byForce: false, savingToDisk: true) + Auth.wrapMainAsync(callback: callback, with: .success(authResult)) + } catch { + Auth.wrapMainAsync(callback: callback, with: .failure(error)) + } + case let .failure(error): + Auth.wrapMainAsync(callback: callback, with: .failure(error)) } - authDataCallback(callback, authResult, nil) } } @@ -2278,11 +2277,12 @@ extension Auth: AuthInterop { } class func wrapMainAsync(callback: ((T?, Error?) -> Void)?, - withParam param: T?, - error: Error?) -> Void { - if let callback { - DispatchQueue.main.async { - callback(param, error) + with result: Result) -> Void { + guard let callback else { return } + DispatchQueue.main.async { + switch result { + case let .success(success): callback(success, nil) + case let .failure(error): callback(nil, error) } } } diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index 3e72368126c..b50636615cc 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -265,10 +265,10 @@ import Foundation /// - Parameter phoneNumber: The phone number to be verified. /// - Parameter callback: The callback to be invoked on the global work queue when the flow is /// finished. - func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, - retryOnInvalidAppCredential: Bool, - uiDelegate: AuthUIDelegate?, - auditFallback: Bool = false) async throws + private func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String, + retryOnInvalidAppCredential: Bool, + uiDelegate: AuthUIDelegate?, + auditFallback: Bool = false) async throws -> String? { let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate) let request = SendVerificationCodeRequest(phoneNumber: phoneNumber, @@ -350,7 +350,7 @@ import Foundation action: .mfaSmsSignIn ) let response = try await auth.backend.call(with: request) - return response.responseInfo?.sessionInfo + return response.responseInfo.sessionInfo } } catch { // For Audit fallback only after rCE check failed @@ -419,9 +419,8 @@ import Foundation MFAEnrollmentID: session.multiFactorInfo?.uid, signInInfo: startMFARequestInfo, requestConfiguration: auth.requestConfiguration) - let response = try await auth.backend.call(with: request) - return response.responseInfo?.sessionInfo + return response.responseInfo.sessionInfo } } catch { return try await handleVerifyErrorWithRetry( diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift index 291821c58f9..35fc6f0bb4b 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/MultiFactor/SignIn/StartMFASignInResponse.swift @@ -16,7 +16,7 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct StartMFASignInResponse: AuthRPCResponse { - var responseInfo: AuthProtoStartMFAPhoneResponseInfo? + let responseInfo: AuthProtoStartMFAPhoneResponseInfo init(dictionary: [String: AnyHashable]) throws { if let data = dictionary["phoneResponseInfo"] as? [String: AnyHashable] { diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift index 7b1815c5925..7cbd45a7a44 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SendVerificationTokenResponse.swift @@ -15,7 +15,7 @@ import Foundation struct SendVerificationCodeResponse: AuthRPCResponse { - var verificationID: String? + let verificationID: String? init(dictionary: [String: AnyHashable]) throws { verificationID = dictionary["sessionInfo"] as? String diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift index 366ccc02023..223c1f9f5f5 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift @@ -80,7 +80,7 @@ import Foundation let result = AuthDataResult(withUser: user, additionalUserInfo: nil) let decoratedCallback = self.auth .signInFlowAuthDataResultCallback(byDecorating: completion) - decoratedCallback(result, nil) + decoratedCallback(.success(result)) } catch { if let completion { completion(nil, error) From 424c02bcb2b7fd89c7bb727e99ef70d571cf236d Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 4 Dec 2024 20:04:22 -0800 Subject: [PATCH 75/98] [auth] Update decoders for consistency with v10 nil behavior (#14212) --- FirebaseAuth/CHANGELOG.md | 4 ++ .../AuthProvider/FacebookAuthProvider.swift | 8 +--- .../AuthProvider/GameCenterAuthProvider.swift | 41 ++++++++----------- .../AuthProvider/GitHubAuthProvider.swift | 7 +--- .../AuthProvider/GoogleAuthProvider.swift | 13 ++---- .../AuthProvider/TwitterAuthProvider.swift | 12 ++---- .../RPC/SignInWithGameCenterRequest.swift | 8 ++-- .../MultiFactor/MultiFactorSession.swift | 2 +- .../SystemService/SecureTokenService.swift | 2 +- 9 files changed, 39 insertions(+), 58 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index fd141940888..9a878b35ca7 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Updated most decoders to be consistent with Firebase 10's behavior + for decoding `nil` values. (#14212) + # 11.6.0 - [added] Added reCAPTCHA Enterprise support for app verification during phone authentication for Firebase Authentication (#14114) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift index 59cb2385425..b02ee16854d 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/FacebookAuthProvider.swift @@ -36,7 +36,7 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRFacebookAuthCredential) class FacebookAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { - let accessToken: String + let accessToken: String? init(withAccessToken accessToken: String) { self.accessToken = accessToken @@ -56,11 +56,7 @@ import Foundation } required init?(coder: NSCoder) { - guard let accessToken = coder.decodeObject(of: NSString.self, forKey: "accessToken") as? String - else { - return nil - } - self.accessToken = accessToken + accessToken = coder.decodeObject(of: NSString.self, forKey: "accessToken") as String? super.init(provider: FacebookAuthProvider.id) } } diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift index 82836ee81b0..935418f27d5 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GameCenterAuthProvider.swift @@ -130,14 +130,14 @@ @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRGameCenterAuthCredential) class GameCenterAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { - let playerID: String + let playerID: String? let teamPlayerID: String? let gamePlayerID: String? let publicKeyURL: URL? let signature: Data? let salt: Data? - let timestamp: UInt64 - let displayName: String + let timestamp: UInt64? + let displayName: String? /// - Parameter playerID: The ID of the Game Center local player. /// - Parameter teamPlayerID: The teamPlayerID of the Game Center local player. @@ -177,27 +177,20 @@ } required init?(coder: NSCoder) { - guard let playerID = coder.decodeObject(of: NSString.self, forKey: "playerID") as? String, - let teamPlayerID = coder.decodeObject( - of: NSString.self, - forKey: "teamPlayerID" - ) as? String, - let gamePlayerID = coder.decodeObject( - of: NSString.self, - forKey: "gamePlayerID" - ) as? String, - let timestamp = coder.decodeObject(of: NSNumber.self, forKey: "timestamp") as? UInt64, - let displayName = coder.decodeObject( - of: NSString.self, - forKey: "displayName" - ) as? String else { - return nil - } - self.playerID = playerID - self.teamPlayerID = teamPlayerID - self.gamePlayerID = gamePlayerID - self.timestamp = timestamp - self.displayName = displayName + playerID = coder.decodeObject(of: NSString.self, forKey: "playerID") as String? + teamPlayerID = coder.decodeObject( + of: NSString.self, + forKey: "teamPlayerID" + ) as String? + gamePlayerID = coder.decodeObject( + of: NSString.self, + forKey: "gamePlayerID" + ) as String? + timestamp = coder.decodeObject(of: NSNumber.self, forKey: "timestamp") as? UInt64 + displayName = coder.decodeObject( + of: NSString.self, + forKey: "displayName" + ) as String? publicKeyURL = coder.decodeObject(forKey: "publicKeyURL") as? URL signature = coder.decodeObject(of: NSData.self, forKey: "signature") as? Data salt = coder.decodeObject(of: NSData.self, forKey: "salt") as? Data diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift index 75b914cbb7a..8765acaa7db 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GitHubAuthProvider.swift @@ -36,7 +36,7 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRGitHubAuthCredential) class GitHubAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { - let token: String + let token: String? init(withToken token: String) { self.token = token @@ -56,10 +56,7 @@ import Foundation } required init?(coder: NSCoder) { - guard let token = coder.decodeObject(of: NSString.self, forKey: "token") as? String else { - return nil - } - self.token = token + token = coder.decodeObject(of: NSString.self, forKey: "token") as String? super.init(provider: GitHubAuthProvider.id) } } diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift index 0f41ac69ce3..38cfa40386e 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/GoogleAuthProvider.swift @@ -38,8 +38,8 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRGoogleAuthCredential) class GoogleAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { - let idToken: String - let accessToken: String + let idToken: String? + let accessToken: String? init(withIDToken idToken: String, accessToken: String) { self.idToken = idToken @@ -62,13 +62,8 @@ import Foundation } required init?(coder: NSCoder) { - guard let idToken = coder.decodeObject(of: NSString.self, forKey: "idToken") as? String, - let accessToken = coder.decodeObject(of: NSString.self, forKey: "accessToken") as? String - else { - return nil - } - self.idToken = idToken - self.accessToken = accessToken + idToken = coder.decodeObject(of: NSString.self, forKey: "idToken") as String? + accessToken = coder.decodeObject(of: NSString.self, forKey: "accessToken") as String? super.init(provider: GoogleAuthProvider.id) } } diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift index f9c32f9d5ad..d735ee0865b 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/TwitterAuthProvider.swift @@ -37,8 +37,8 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRTwitterAuthCredential) class TwitterAuthCredential: AuthCredential, NSSecureCoding, @unchecked Sendable { - let token: String - let secret: String + let token: String? + let secret: String? init(withToken token: String, secret: String) { self.token = token @@ -61,12 +61,8 @@ import Foundation } required init?(coder: NSCoder) { - guard let token = coder.decodeObject(of: NSString.self, forKey: "token") as? String, - let secret = coder.decodeObject(of: NSString.self, forKey: "secret") as? String else { - return nil - } - self.token = token - self.secret = secret + token = coder.decodeObject(of: NSString.self, forKey: "token") as String? + secret = coder.decodeObject(of: NSString.self, forKey: "secret") as String? super.init(provider: TwitterAuthProvider.id) } } diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift index 7d722326f71..34f94f87489 100644 --- a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithGameCenterRequest.swift @@ -22,7 +22,7 @@ class SignInWithGameCenterRequest: IdentityToolkitRequest, AuthRPCRequest { typealias Response = SignInWithGameCenterResponse /// The playerID to verify. - var playerID: String + var playerID: String? /// The team player ID of the Game Center local player. var teamPlayerID: String? @@ -40,7 +40,7 @@ class SignInWithGameCenterRequest: IdentityToolkitRequest, AuthRPCRequest { var salt: Data /// The date and time that the signature was created. - var timestamp: UInt64 + var timestamp: UInt64? /// The STS Access Token for the authenticated user, only needed for linking the user. var accessToken: String? @@ -57,10 +57,10 @@ class SignInWithGameCenterRequest: IdentityToolkitRequest, AuthRPCRequest { /// - Parameter salt: A random string used to compute the hash and keep it randomized. /// - Parameter timestamp: The date and time that the signature was created. /// - Parameter displayName: The display name of the Game Center player. - init(playerID: String, teamPlayerID: String?, gamePlayerID: String?, + init(playerID: String?, teamPlayerID: String?, gamePlayerID: String?, publicKeyURL: URL, signature: Data, salt: Data, - timestamp: UInt64, displayName: String?, + timestamp: UInt64?, displayName: String?, requestConfiguration: AuthRequestConfiguration) { self.playerID = playerID self.teamPlayerID = teamPlayerID diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift index cc83e3f2f0d..42067fd30c3 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift @@ -46,7 +46,7 @@ import Foundation return .init(idToken: currentUser.tokenService.accessToken, currentUser: currentUser) } - init(idToken: String, currentUser: User) { + init(idToken: String?, currentUser: User) { self.idToken = idToken self.currentUser = currentUser } diff --git a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift index 6bdee4c395a..a24ce10aabc 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/SecureTokenService.swift @@ -123,7 +123,7 @@ class SecureTokenService: NSObject, NSSecureCoding { /// The cached access token. /// - /// This method is specifically for providing the access token to internal clients during + /// This method is specifically for providing the access token to internal clients during /// deserialization and sign-in events, and should not be used to retrieve the access token by /// anyone else. var accessToken: String From 16381c753c8ff2fe2900fd75b050ac27dacda2ef Mon Sep 17 00:00:00 2001 From: Tejas Deshpande Date: Thu, 5 Dec 2024 15:51:07 -0500 Subject: [PATCH 76/98] Update the method documentation of recordError (#14198) #no-changelog --- .../Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h b/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h index 7ecad24abf7..c923f4c66fc 100644 --- a/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h +++ b/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h @@ -126,8 +126,8 @@ NS_SWIFT_NAME(Crashlytics) * relayed to Crashlytics on a subsequent launch of your application. * * @param error Non-fatal error to be recorded - * @param userInfo Additional keys and values to send with the logged error. These parameters are - * added to Crashlytics global list of keys and values that live with the session. + * @param userInfo Additional keys and values to send with the logged error. These keys and values + * are added to the error, in addition to the Crashlytics global list of keys and values. */ - (void)recordError:(NSError *)error userInfo:(nullable NSDictionary *)userInfo From c62aa2b1c0dc4e61d596d545137edad080dff101 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 9 Dec 2024 08:36:18 -0800 Subject: [PATCH 77/98] [infra][auth] auth ci to Xcode 16.1 (#14228) --- .github/workflows/auth.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index ffb858b589b..3b7a6d7989a 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -59,7 +59,7 @@ jobs: podspec: [FirebaseAuthInterop.podspec, FirebaseAuth.podspec] target: [ios, tvos, macos --skip-tests --allow-warnings, watchos] os: [macos-15] - xcode: [Xcode_16] + xcode: [Xcode_16.1] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -115,22 +115,22 @@ jobs: xcode: Xcode_15.4 target: iOS spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: iOS spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: tvOS spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: macOS spmbuildonly - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: watchOS spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: catalyst spm - os: macos-15 - xcode: Xcode_16 + xcode: Xcode_16.1 target: visionOS spm runs-on: ${{ matrix.os }} steps: @@ -185,7 +185,7 @@ jobs: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/AuthSample/Credentials.swift.gpg \ FirebaseAuth/Tests/SampleSwift/SwiftApiTests/Credentials.swift "$plist_secret" - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer - uses: nick-fields/retry@v3 with: timeout_minutes: 120 From acc4bbf505659934ced4214715d9fd7c65fab8bf Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 9 Dec 2024 13:03:12 -0800 Subject: [PATCH 78/98] Auth Unit Test Fixes (#14223) --- .../AuthProvider/PhoneAuthProvider.swift | 2 +- .../SystemService/AuthAPNSTokenManager.swift | 2 +- .../AuthAppCredentialManager.swift | 2 +- .../AuthNotificationManager.swift | 2 +- .../Tests/Unit/AuthBackendTests.swift | 18 +- FirebaseAuth/Tests/Unit/AuthTests.swift | 250 +++++++++--------- .../Tests/Unit/CreateAuthURITests.swift | 16 +- .../Tests/Unit/DeleteAccountTests.swift | 6 +- .../Tests/Unit/EmailLinkSignInTests.swift | 29 +- .../Unit/Fakes/FakeBackendRPCIssuer.swift | 98 +++---- .../Tests/Unit/GetAccountInfoTests.swift | 5 +- .../Unit/GetOOBConfirmationCodeTests.swift | 10 +- .../Tests/Unit/GetProjectConfigTests.swift | 8 +- .../Tests/Unit/OAuthProviderTests.swift | 20 +- .../Tests/Unit/PhoneAuthProviderTests.swift | 71 ++--- FirebaseAuth/Tests/Unit/RPCBaseTests.swift | 8 +- .../Tests/Unit/ResetPasswordTests.swift | 4 +- .../Tests/Unit/RevokeTokenTests.swift | 2 +- .../Unit/SendVerificationCodeTests.swift | 2 +- .../Tests/Unit/SetAccountInfoTests.swift | 2 +- .../Unit/SignInWithGameCenterTests.swift | 2 +- .../Tests/Unit/SignUpNewUserTests.swift | 2 +- FirebaseAuth/Tests/Unit/UserTests.swift | 183 ++++++------- .../Tests/Unit/VerifyAssertionTests.swift | 4 +- .../Tests/Unit/VerifyClientTests.swift | 2 +- .../Tests/Unit/VerifyCustomTokenTests.swift | 2 +- .../Tests/Unit/VerifyPasswordTests.swift | 2 +- .../Tests/Unit/VerifyPhoneNumberTests.swift | 4 +- 28 files changed, 378 insertions(+), 380 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift index b50636615cc..8c7a6982fd4 100644 --- a/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift +++ b/FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift @@ -525,7 +525,7 @@ import Foundation ) } - return try await withCheckedThrowingContinuation { continuation in + return try await withUnsafeThrowingContinuation { continuation in self.auth.authURLPresenter.present(url, uiDelegate: uiDelegate, callbackMatcher: callbackMatcher) { callbackURL, error in diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift index ff677b8771b..479918165e9 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAPNSTokenManager.swift @@ -74,7 +74,7 @@ } func getToken() async throws -> AuthAPNSToken { - return try await withCheckedThrowingContinuation { continuation in + return try await withUnsafeThrowingContinuation { continuation in self.getTokenInternal { result in switch result { case let .success(token): diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredentialManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredentialManager.swift index 0c83875a8d1..a513dd1cbb0 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredentialManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthAppCredentialManager.swift @@ -65,7 +65,7 @@ func didStartVerification(withReceipt receipt: String, timeout: TimeInterval) async -> AuthAppCredential { - return await withCheckedContinuation { continuation in + return await withUnsafeContinuation { continuation in self.didStartVerificationInternal(withReceipt: receipt, timeout: timeout) { credential in continuation.resume(returning: credential) } diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift index 2cfd76ca2de..296ab5d4b28 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift @@ -114,7 +114,7 @@ } func checkNotificationForwarding() async -> Bool { - return await withCheckedContinuation { continuation in + return await withUnsafeContinuation { continuation in checkNotificationForwardingInternal { value in continuation.resume(returning: value) } diff --git a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift index 6056bbae362..748a5ba1982 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift @@ -90,7 +90,7 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { let responseError = NSError(domain: self.kFakeErrorDomain, code: self.kFakeErrorCode) - try self.rpcIssuer.respond(withData: nil, error: responseError) + return (nil, responseError) } do { let _ = try await authBackend.call(with: request) @@ -122,7 +122,7 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { let responseError = NSError(domain: self.kFakeErrorDomain, code: self.kFakeErrorCode) - try self.rpcIssuer.respond(withData: data, error: responseError) + return (data, error: responseError) } do { let _ = try await authBackend.call(with: request) @@ -159,7 +159,7 @@ class AuthBackendTests: RPCBaseTests { let data = "Some non-JSON value.".data(using: .utf8) let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { - try self.rpcIssuer.respond(withData: data, error: nil) + (data, nil) } do { let _ = try await authBackend.call(with: request) @@ -201,7 +201,7 @@ class AuthBackendTests: RPCBaseTests { let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode) let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { - try self.rpcIssuer.respond(withData: data, error: responseError) + (data, responseError) } do { let _ = try await authBackend.call(with: request) @@ -243,7 +243,7 @@ class AuthBackendTests: RPCBaseTests { let data = "[]".data(using: .utf8) let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { - try self.rpcIssuer.respond(withData: data, error: nil) + (data, nil) } do { let _ = try await authBackend.call(with: request) @@ -277,8 +277,8 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { let responseError = NSError(domain: self.kFakeErrorDomain, code: self.kFakeErrorCode) - try self.rpcIssuer.respond(serverErrorMessage: kErrorMessageCaptchaRequired, - error: responseError) + return try self.rpcIssuer.respond(serverErrorMessage: kErrorMessageCaptchaRequired, + error: responseError) } do { let _ = try await authBackend.call(with: request) @@ -317,7 +317,7 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withRequestBody: [:]) rpcIssuer.respondBlock = { let responseError = NSError(domain: self.kFakeErrorDomain, code: self.kFakeErrorCode) - try self.rpcIssuer.respond( + return try self.rpcIssuer.respond( serverErrorMessage: kErrorMessageCaptchaCheckFailed, error: responseError ) @@ -427,7 +427,7 @@ class AuthBackendTests: RPCBaseTests { let request = FakeRequest(withRequestBody: [:]) let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode) rpcIssuer.respondBlock = { - let _ = try self.rpcIssuer.respond(withJSON: [:], error: responseError) + try self.rpcIssuer.respond(withJSON: [:], error: responseError) } do { let _ = try await authBackend.call(with: request) diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index 9bf57b39dd3..fe7be777cc9 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -84,7 +84,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.endpoint, "createAuthUri") XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) - try self.rpcIssuer.respond(withJSON: ["signinMethods": allSignInMethods]) + return try self.rpcIssuer.respond(withJSON: ["signinMethods": allSignInMethods]) } auth?.fetchSignInMethods(forEmail: kEmail) { signInMethods, error in @@ -106,7 +106,7 @@ class AuthTests: RPCBaseTests { rpcIssuer.respondBlock = { let message = "TOO_MANY_ATTEMPTS_TRY_LATER" - try self.rpcIssuer.respond(serverErrorMessage: message) + return try self.rpcIssuer.respond(serverErrorMessage: message) } auth?.fetchSignInMethods(forEmail: kEmail) { signInMethods, error in XCTAssertTrue(Thread.isMainThread) @@ -137,9 +137,9 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.verificationID, kVerificationID) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() @@ -241,10 +241,10 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.oobCode, fakeCode) XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() auth?.signIn(withEmail: kEmail, link: link) { authResult, error in @@ -309,10 +309,10 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": kRefreshToken]) } try auth?.signOut() @@ -362,7 +362,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") + return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") } rpcIssuer.nextRespondBlock = { // 4. Validate again the created Request instance after the recaptcha retry. @@ -374,10 +374,10 @@ class AuthTests: RPCBaseTests { request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse, recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 5. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": kRefreshToken]) } try auth?.signOut() @@ -425,10 +425,10 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": kRefreshToken]) } try auth?.signOut() @@ -495,7 +495,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } try auth?.signOut() auth? @@ -549,9 +549,9 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["email": self.kEmail, - "requestType": verifyEmailRequestType, - "newEmail": kNewEmail]) + return try self.rpcIssuer.respond(withJSON: ["email": self.kEmail, + "requestType": verifyEmailRequestType, + "newEmail": kNewEmail]) } try auth?.signOut() auth?.checkActionCode(kFakeOobCode) { info, error in @@ -601,7 +601,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } try auth?.signOut() auth?.applyActionCode(kFakeOobCode) { error in @@ -650,7 +650,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.oobCode, self.kFakeOobCode) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["email": self.kEmail]) + return try self.rpcIssuer.respond(withJSON: ["email": self.kEmail]) } try auth?.signOut() auth?.verifyPasswordResetCode(kFakeOobCode) { email, error in @@ -706,9 +706,9 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.email, self.kEmail) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() let emailCredential = EmailAuthProvider.credential( @@ -778,9 +778,9 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.email, self.kEmail) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() let emailCredential = EmailAuthProvider.credential(withEmail: kEmail, password: kFakePassword) @@ -876,14 +876,14 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } try auth.signOut() auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in @@ -919,7 +919,7 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED") + return try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED") } try auth.signOut() auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in @@ -953,15 +953,15 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName, - "needConfirmation": true]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName, + "needConfirmation": true]) } try auth.signOut() let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken, @@ -997,14 +997,14 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } try auth.signOut() auth.signIn(with: FakeProvider(), uiDelegate: nil) { authResult, error in @@ -1043,14 +1043,14 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kGoogleDisplayName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kGoogleDisplayName]) } try auth.signOut() let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken, @@ -1095,7 +1095,7 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(serverErrorMessage: "EMAIL_EXISTS") + return try self.rpcIssuer.respond(serverErrorMessage: "EMAIL_EXISTS") } try auth.signOut() let googleCredential = GoogleAuthProvider.credential(withIDToken: kGoogleIDToken, @@ -1139,16 +1139,16 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": AuthProviderID.apple.rawValue, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "firstName": kFirst, - "lastName": kLast, - "username": self.kGoogleDisplayName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": AuthProviderID.apple.rawValue, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "firstName": kFirst, + "lastName": kLast, + "username": self.kGoogleDisplayName]) } try auth.signOut() let appleCredential = OAuthProvider.appleCredential(withIDToken: kAppleIDToken, @@ -1194,10 +1194,10 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() auth?.signInAnonymously { authResult, error in @@ -1257,10 +1257,10 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": false, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": false, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() auth?.signIn(withCustomToken: kCustomToken) { authResult, error in @@ -1327,10 +1327,10 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in @@ -1375,7 +1375,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") + return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") } rpcIssuer.nextRespondBlock = { // 4. Validate again the created Request instance after the recaptcha retry. @@ -1387,10 +1387,10 @@ class AuthTests: RPCBaseTests { request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse, recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 5. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() @@ -1432,10 +1432,10 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } try auth?.signOut() auth?.createUser(withEmail: kEmail, password: kFakePassword) { authResult, error in @@ -1532,7 +1532,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } auth?.sendPasswordReset(withEmail: kEmail) { error in // 4. After the response triggers the callback, verify success. @@ -1561,7 +1561,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") + return try self.rpcIssuer.respond(serverErrorMessage: "MISSING_RECAPTCHA_TOKEN") } rpcIssuer.nextRespondBlock = { // 4. Validate again the created Request instance after the recaptcha retry. @@ -1571,10 +1571,10 @@ class AuthTests: RPCBaseTests { request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse, recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 5. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } auth?.sendPasswordReset(withEmail: kEmail) { error in @@ -1601,7 +1601,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) // 3. Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } auth?.sendPasswordReset(withEmail: kEmail) { error in // 4. After the response triggers the callback, verify success. @@ -1651,7 +1651,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } auth?.sendSignInLink(toEmail: kEmail, actionCodeSettings: fakeActionCodeSettings()) { error in @@ -1683,7 +1683,7 @@ class AuthTests: RPCBaseTests { recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 3. Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } rpcIssuer.nextRespondBlock = { // 4. Validate again the created Request instance after the recaptcha retry. @@ -1693,10 +1693,10 @@ class AuthTests: RPCBaseTests { request.injectRecaptchaFields(recaptchaResponse: AuthTests.kFakeRecaptchaResponse, recaptchaVersion: AuthTests.kFakeRecaptchaVersion) // 5. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, - "email": self.kEmail, - "isNewUser": true, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": AuthTests.kAccessToken, + "email": self.kEmail, + "isNewUser": true, + "refreshToken": self.kRefreshToken]) } auth?.sendSignInLink(toEmail: kEmail, @@ -1726,7 +1726,7 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.handleCodeInApp) // 3. Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } auth?.sendSignInLink(toEmail: kEmail, actionCodeSettings: fakeActionCodeSettings()) { error in @@ -1797,7 +1797,7 @@ class AuthTests: RPCBaseTests { let kFakeErrorDomain = "fakeDomain" let kFakeErrorCode = -1 let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode) - try self.rpcIssuer.respond(withData: nil, error: responseError) + return (nil, responseError) } // Clear fake so we can inject error rpcIssuer.fakeGetAccountProviderJSON = nil @@ -1916,7 +1916,7 @@ class AuthTests: RPCBaseTests { XCTAssertEqual(request.tokenType, .authorizationCode) // Send the response from the fake backend. - _ = try self.rpcIssuer.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } auth?.revokeToken(withAuthorizationCode: code) { error in // Verify callback success. @@ -1932,17 +1932,17 @@ class AuthTests: RPCBaseTests { func testRevokeTokenMissingCallback() throws { try waitForSignInWithAccessToken() let code = "code" - let issuer = rpcIssuer + let issuer = try XCTUnwrap(rpcIssuer) - issuer?.respondBlock = { - let request = try XCTUnwrap(issuer?.request as? RevokeTokenRequest) + issuer.respondBlock = { + let request = try XCTUnwrap(issuer.request as? RevokeTokenRequest) XCTAssertEqual(request.apiKey, AuthTests.kFakeAPIKey) XCTAssertEqual(request.providerID, AuthProviderID.apple.rawValue) XCTAssertEqual(request.token, code) XCTAssertEqual(request.tokenType, .authorizationCode) // Send the response from the fake backend. - _ = try issuer?.respond(withJSON: [:]) + return try issuer.respond(withJSON: [:]) } auth?.revokeToken(withAuthorizationCode: code) } @@ -2402,11 +2402,11 @@ class AuthTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken, - "email": self.kEmail, - "isNewUser": true, - "expiresIn": "3600", - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken, + "email": self.kEmail, + "isNewUser": true, + "expiresIn": "3600", + "refreshToken": kRefreshToken]) } auth?.signIn(withEmail: kEmail, password: kFakePassword) { authResult, error in // 4. After the response triggers the callback, verify the returned result. diff --git a/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift b/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift index 334091d21fd..fde2b4d155c 100644 --- a/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift +++ b/FirebaseAuth/Tests/Unit/CreateAuthURITests.swift @@ -71,9 +71,10 @@ class CreateAuthURITests: RPCBaseTests { func testSuccessfulCreateAuthURIResponse() async throws { let kAuthUriKey = "authUri" let kTestAuthUri = "AuthURI" + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [kAuthUriKey: kTestAuthUri]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: [kAuthUriKey: kTestAuthUri]) } let rpcResponse = try await authBackend.call(with: makeAuthURIRequest()) XCTAssertEqual(rpcResponse.authURI, kTestAuthUri) @@ -83,17 +84,18 @@ class CreateAuthURITests: RPCBaseTests { let kTestExpectedKind = "identitytoolkit#CreateAuthUriResponse" let kTestProviderID1 = "google.com" let kTestProviderID2 = "facebook.com" + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) - rpcIssuer?.respondBlock = { - try self.rpcIssuer? + rpcIssuer.respondBlock = { + try self.rpcIssuer .respond(withJSON: ["kind": kTestExpectedKind, "allProviders": [kTestProviderID1, kTestProviderID2]]) } let rpcResponse = try await authBackend.call(with: makeAuthURIRequest()) - XCTAssertEqual(rpcIssuer?.requestURL?.absoluteString, kExpectedAPIURL) - XCTAssertEqual(rpcIssuer?.decodedRequest?["identifier"] as? String, kTestIdentifier) - XCTAssertEqual(rpcIssuer?.decodedRequest?["continueUri"] as? String, kTestContinueURI) + XCTAssertEqual(rpcIssuer.requestURL?.absoluteString, kExpectedAPIURL) + XCTAssertEqual(rpcIssuer.decodedRequest?["identifier"] as? String, kTestIdentifier) + XCTAssertEqual(rpcIssuer.decodedRequest?["continueUri"] as? String, kTestContinueURI) XCTAssertEqual(rpcResponse.allProviders?.count, 2) XCTAssertEqual(rpcResponse.allProviders?.first, kTestProviderID1) diff --git a/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift b/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift index a968a02e3e8..5dabf73662b 100644 --- a/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift +++ b/FirebaseAuth/Tests/Unit/DeleteAccountTests.swift @@ -61,8 +61,10 @@ class DeleteAccountTests: RPCBaseTests { @brief This test checks for a successful response */ func testSuccessfulDeleteAccountResponse() async throws { - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [:]) + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) + + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: [:]) } let rpcResponse = try await authBackend.call(with: makeDeleteAccountRequest()) XCTAssertNotNil(rpcResponse) diff --git a/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift b/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift index ce4b2dd57d5..49e9e7dabb9 100644 --- a/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift +++ b/FirebaseAuth/Tests/Unit/EmailLinkSignInTests.swift @@ -54,16 +54,18 @@ class EmailLinkSignInTests: RPCBaseTests { @brief Tests the email link sign-in request with mandatory parameters. */ func testEmailLinkRequest() async throws { - rpcIssuer?.respondBlock = { + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) + + rpcIssuer.respondBlock = { XCTAssertEqual(self.rpcIssuer?.requestURL?.absoluteString, self.kExpectedAPIURL) guard let requestDictionary = self.rpcIssuer?.decodedRequest as? [AnyHashable: String] else { XCTFail("decodedRequest is not a dictionary") - return + return (nil, nil) } XCTAssertEqual(requestDictionary[self.kEmailKey], self.kTestEmail) XCTAssertEqual(requestDictionary[self.kOOBCodeKey], self.kTestOOBCode) XCTAssertNil(requestDictionary[self.kIDTokenKey]) - try self.rpcIssuer?.respond(withJSON: [:]) // unblock the await + return try self.rpcIssuer.respond(withJSON: [:]) // unblock the await } let _ = try await authBackend.call(with: makeEmailLinkSignInRequest()) } @@ -75,17 +77,18 @@ class EmailLinkSignInTests: RPCBaseTests { let kTestIDToken = "testIDToken" let request = makeEmailLinkSignInRequest() request.idToken = kTestIDToken + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) - rpcIssuer?.respondBlock = { + rpcIssuer.respondBlock = { XCTAssertEqual(self.rpcIssuer?.requestURL?.absoluteString, self.kExpectedAPIURL) guard let requestDictionary = self.rpcIssuer?.decodedRequest as? [AnyHashable: String] else { XCTFail("decodedRequest is not a dictionary") - return + return (nil, nil) } XCTAssertEqual(requestDictionary[self.kEmailKey], self.kTestEmail) XCTAssertEqual(requestDictionary[self.kOOBCodeKey], self.kTestOOBCode) XCTAssertEqual(requestDictionary[self.kIDTokenKey], kTestIDToken) - try self.rpcIssuer?.respond(withJSON: [:]) // unblock the await + return try self.rpcIssuer.respond(withJSON: [:]) // unblock the await } let _ = try await authBackend.call(with: request) } @@ -108,12 +111,14 @@ class EmailLinkSignInTests: RPCBaseTests { let kTestTokenExpirationTimeInterval: Double = 55 * 60 let kTestRefreshToken = "testRefreshToken" - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": kTestIDTokenResponse, - "email": kTestEmailResponse, - "isNewUser": true, - "expiresIn": "\(kTestTokenExpirationTimeInterval)", - "refreshToken": kTestRefreshToken]) + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) + + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: ["idToken": kTestIDTokenResponse, + "email": kTestEmailResponse, + "isNewUser": true, + "expiresIn": "\(kTestTokenExpirationTimeInterval)", + "refreshToken": kTestRefreshToken]) } let response = try await authBackend.call(with: makeEmailLinkSignInRequest()) diff --git a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift index ceca635dacf..ec931c0c859 100644 --- a/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift +++ b/FirebaseAuth/Tests/Unit/Fakes/FakeBackendRPCIssuer.swift @@ -61,14 +61,14 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda /** @var verifyRequester @brief Optional function to run tests on the request. */ - var verifyRequester: ((SendVerificationCodeRequest) -> Void)? - var verifyClientRequester: ((VerifyClientRequest) -> Void)? - var projectConfigRequester: ((GetProjectConfigRequest) -> Void)? - var verifyPasswordRequester: ((VerifyPasswordRequest) -> Void)? + var verifyRequester: ((SendVerificationCodeRequest) -> (Data?, Error?))? + var verifyClientRequester: ((VerifyClientRequest) -> (Data?, Error?))? + var projectConfigRequester: ((GetProjectConfigRequest) -> (Data?, Error?))? + var verifyPasswordRequester: ((VerifyPasswordRequest) -> (Data?, Error?))? var verifyPhoneNumberRequester: ((VerifyPhoneNumberRequest) -> Void)? - var respondBlock: (() throws -> Void)? - var nextRespondBlock: (() throws -> Void)? + var respondBlock: (() throws -> (Data?, Error?))? + var nextRespondBlock: (() throws -> (Data?, Error?))? var fakeGetAccountProviderJSON: [[String: AnyHashable]]? var fakeSecureTokenServiceJSON: [String: AnyHashable]? @@ -80,35 +80,23 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda func asyncCallToURL(with request: T, body: Data?, contentType: String) async -> (Data?, Error?) where T: FirebaseAuth.AuthRPCRequest { - return await withCheckedContinuation { continuation in - self.asyncCallToURL(with: request, body: body, contentType: contentType) { data, error in - continuation.resume(returning: (data, error)) - } - } - } - - func asyncCallToURL(with request: T, - body: Data?, - contentType: String, - completionHandler: @escaping ((Data?, Error?) -> Void)) { self.contentType = contentType - handler = completionHandler self.request = request requestURL = request.requestURL() // TODO: See if we can use the above generics to avoid all this. if let verifyRequester, let verifyRequest = request as? SendVerificationCodeRequest { - verifyRequester(verifyRequest) + return verifyRequester(verifyRequest) } else if let verifyClientRequester, let verifyClientRequest = request as? VerifyClientRequest { - verifyClientRequester(verifyClientRequest) + return verifyClientRequester(verifyClientRequest) } else if let projectConfigRequester, let projectConfigRequest = request as? GetProjectConfigRequest { - projectConfigRequester(projectConfigRequest) + return projectConfigRequester(projectConfigRequest) } else if let verifyPasswordRequester, let verifyPasswordRequest = request as? VerifyPasswordRequest { - verifyPasswordRequester(verifyPasswordRequest) + return verifyPasswordRequester(verifyPasswordRequest) } else if let verifyPhoneNumberRequester, let verifyPhoneNumberRequest = request as? VerifyPhoneNumberRequest { verifyPhoneNumberRequester(verifyPhoneNumberRequest) @@ -116,10 +104,10 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda if let _ = request as? GetAccountInfoRequest, let json = fakeGetAccountProviderJSON { - guard let _ = try? respond(withJSON: ["users": json]) else { + guard let (data, error) = try? respond(withJSON: ["users": json]) else { fatalError("fakeGetAccountProviderJSON respond failed") } - return + return (data, error) } else if let _ = request as? GetRecaptchaConfigRequest { if rceMode != "OFF" { // Check if reCAPTCHA is enabled let recaptchaKey = recaptchaSiteKey // iOS key from your config @@ -127,40 +115,38 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": rceMode], ["provider": "PHONE_PROVIDER", "enforcementState": rceMode], ] - guard let _ = try? respond(withJSON: [ + guard let (data, error) = try? respond(withJSON: [ "recaptchaKey": recaptchaKey, "recaptchaEnforcementState": enforcementState, ]) else { fatalError("GetRecaptchaConfigRequest respond failed") } + return (data, error) } else { // reCAPTCHA OFF let enforcementState = [ ["provider": "EMAIL_PASSWORD_PROVIDER", "enforcementState": "OFF"], ["provider": "PHONE_PROVIDER", "enforcementState": "OFF"], ] - guard let _ = try? respond(withJSON: [ + guard let (data, error) = try? respond(withJSON: [ "recaptchaEnforcementState": enforcementState, ]) else { fatalError("GetRecaptchaConfigRequest respond failed") } + return (data, error) } - return } else if let _ = request as? SecureTokenRequest { if let secureTokenNetworkError { - guard let _ = try? respond(withData: nil, - error: secureTokenNetworkError) else { - fatalError("Failed to generate secureTokenNetworkError") - } + return (nil, secureTokenNetworkError) } else if let secureTokenErrorString { - guard let _ = try? respond(serverErrorMessage: secureTokenErrorString) else { + guard let (data, error) = try? respond(serverErrorMessage: secureTokenErrorString) else { fatalError("Failed to generate secureTokenErrorString") } - return + return (data, error) } else if let json = fakeSecureTokenServiceJSON { - guard let _ = try? respond(withJSON: json) else { + guard let (data, error) = try? respond(withJSON: json) else { fatalError("fakeGetAccountProviderJSON respond failed") } - return + return (data, error) } } if let body = body { @@ -180,26 +166,28 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda } if let respondBlock { do { - try respondBlock() + let (data, error) = try respondBlock() + self.respondBlock = nextRespondBlock + nextRespondBlock = nil + return (data, error) } catch { - XCTFail("Unexpected exception in respondBlock") + return (nil, error) } - self.respondBlock = nextRespondBlock - nextRespondBlock = nil } + fatalError("Should never get here") } - func respond(serverErrorMessage errorMessage: String) throws { + func respond(serverErrorMessage errorMessage: String) throws -> (Data, Error?) { let error = NSError(domain: NSCocoaErrorDomain, code: 0) - try respond(serverErrorMessage: errorMessage, error: error) + return try respond(serverErrorMessage: errorMessage, error: error) } - func respond(serverErrorMessage errorMessage: String, error: NSError) throws { - _ = try respond(withJSON: ["error": ["message": errorMessage]], error: error) + func respond(serverErrorMessage errorMessage: String, error: NSError) throws -> (Data, Error?) { + return try respond(withJSON: ["error": ["message": errorMessage]], error: error) } - @discardableResult func respond(underlyingErrorMessage errorMessage: String, - message: String = "See the reason") throws -> Data { + func respond(underlyingErrorMessage errorMessage: String, + message: String = "See the reason") throws -> (Data, Error?) { let error = NSError(domain: NSCocoaErrorDomain, code: 0) return try respond( withJSON: ["error": ["message": message, @@ -208,21 +196,9 @@ final class FakeBackendRPCIssuer: AuthBackendRPCIssuerProtocol, @unchecked Senda ) } - @discardableResult func respond(withJSON json: [String: Any], - error: NSError? = nil) throws -> Data { - let data = try JSONSerialization.data(withJSONObject: json, - options: JSONSerialization.WritingOptions.prettyPrinted) - try respond(withData: data, error: error) - return data - } - - func respond(withData data: Data?, error: NSError?) throws { - let handler = try XCTUnwrap(handler, "There is no pending RPC request.") - XCTAssertTrue( - (data != nil) || (error != nil), - "At least one of: data or error should be been non-nil." - ) - self.handler = nil - handler(data, error) + func respond(withJSON json: [String: Any], error: NSError? = nil) throws -> (Data, Error?) { + return try (JSONSerialization.data(withJSONObject: json, + options: JSONSerialization.WritingOptions.prettyPrinted), + error) } } diff --git a/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift b/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift index dff1e74936e..ec5eba4e2d0 100644 --- a/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift +++ b/FirebaseAuth/Tests/Unit/GetAccountInfoTests.swift @@ -96,9 +96,10 @@ class GetAccountInfoTests: RPCBaseTests { kEmailVerifiedKey: true, kPasswordHashKey: kTestPasswordHash, ] as [String: Any]] + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["users": usersIn]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: ["users": usersIn]) } let rpcResponse = try await authBackend.call(with: makeGetAccountInfoRequest()) diff --git a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift index 631bab3a723..a504f022e49 100644 --- a/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift +++ b/FirebaseAuth/Tests/Unit/GetOOBConfirmationCodeTests.swift @@ -191,13 +191,14 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { it succeeds, and we get the OOB Code decoded correctly. */ func testSuccessfulOOBResponse() async throws { + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) for request in [ getPasswordResetRequest, getSignInWithEmailRequest, getEmailVerificationRequest, ] { - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [self.kOOBCodeKey: self.kTestOOBCode]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: [self.kOOBCodeKey: self.kTestOOBCode]) } let response = try await authBackend.call(with: request()) XCTAssertEqual(response.OOBCode, kTestOOBCode) @@ -209,13 +210,14 @@ class GetOOBConfirmationCodeTests: RPCBaseTests { response value. It should still succeed. */ func testSuccessfulOOBResponseWithoutOOBCode() async throws { + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) for request in [ getPasswordResetRequest, getSignInWithEmailRequest, getEmailVerificationRequest, ] { - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [:]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: [:]) } let response = try await authBackend.call(with: request()) XCTAssertNil(response.OOBCode) diff --git a/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift b/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift index 6dbe4c644c6..a49e7709fa0 100644 --- a/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift +++ b/FirebaseAuth/Tests/Unit/GetProjectConfigTests.swift @@ -55,10 +55,10 @@ class GetProjectConfigTests: RPCBaseTests { let kTestProjectID = "21141651616" let kTestDomain1 = "localhost" let kTestDomain2 = "example.firebaseapp.com" - - rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["projectId": kTestProjectID, - "authorizedDomains": [kTestDomain1, kTestDomain2]]) + let rpcIssuer = try XCTUnwrap(self.rpcIssuer) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(withJSON: ["projectId": kTestProjectID, + "authorizedDomains": [kTestDomain1, kTestDomain2]]) } let rpcResponse = try await authBackend.call(with: makeGetProjectConfigRequest()) XCTAssertEqual(rpcResponse.projectID, kTestProjectID) diff --git a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift index a5a330babf7..d4b2b47d6f2 100644 --- a/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/OAuthProviderTests.swift @@ -301,22 +301,20 @@ import FirebaseCore // 1. Setup fakes and parameters for getCredential. if !OAuthProviderTests.testEmulator { let projectConfigExpectation = self.expectation(description: "projectConfiguration") - rpcIssuer?.projectConfigRequester = { request in + rpcIssuer.projectConfigRequester = { request in // 3. Validate the created Request instance. XCTAssertEqual(request.apiKey, OAuthProviderTests.kFakeAPIKey) XCTAssertEqual(request.endpoint, "getProjectConfig") // 4. Fulfill the expectation. projectConfigExpectation.fulfill() - kAuthGlobalWorkQueue.async { - do { - // 5. Send the response from the fake backend. - try self.rpcIssuer? - .respond(withJSON: ["authorizedDomains": [ - OAuthProviderTests.kFakeAuthorizedWebDomain, - OAuthProviderTests.kFakeAuthorizedDomain]]) - } catch { - XCTFail("Failure sending response: \(error)") - } + do { + // 5. Send the response from the fake backend. + return try self.rpcIssuer.respond(withJSON: ["authorizedDomains": [ + OAuthProviderTests.kFakeAuthorizedWebDomain, + OAuthProviderTests.kFakeAuthorizedDomain]]) + } catch { + XCTFail("Failure sending response: \(error)") + return (nil, nil) } } } diff --git a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift index fd7291f6820..94880a3d856 100644 --- a/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift +++ b/FirebaseAuth/Tests/Unit/PhoneAuthProviderTests.swift @@ -110,17 +110,18 @@ AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) rpcIssuer.rceMode = "ENFORCE" let requestExpectation = expectation(description: "verifyRequester") - rpcIssuer?.verifyRequester = { request in + rpcIssuer.verifyRequester = { request in XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) XCTAssertEqual(request.captchaResponse, self.kCaptchaResponse) XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) requestExpectation.fulfill() do { - try self.rpcIssuer? + return try self.rpcIssuer .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } do { @@ -157,13 +158,12 @@ XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) requestExpectation.fulfill() do { - try self.rpcIssuer? - .respond( - serverErrorMessage: "INVALID_RECAPTCHA_TOKEN", - error: AuthErrorUtils.invalidRecaptchaTokenError() as NSError - ) + return try self.rpcIssuer + .respond(serverErrorMessage: "INVALID_RECAPTCHA_TOKEN", + error: AuthErrorUtils.invalidRecaptchaTokenError() as NSError) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } do { @@ -218,17 +218,18 @@ AuthRecaptchaVerifier.setShared(mockVerifier, auth: auth) rpcIssuer.rceMode = "AUDIT" let requestExpectation = expectation(description: "verifyRequester") - rpcIssuer?.verifyRequester = { request in + rpcIssuer.verifyRequester = { request in XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) XCTAssertEqual(request.captchaResponse, self.kCaptchaResponse) XCTAssertEqual(request.recaptchaVersion, "RECAPTCHA_ENTERPRISE") XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) requestExpectation.fulfill() do { - try self.rpcIssuer? + return try self.rpcIssuer .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } do { @@ -263,13 +264,14 @@ XCTAssertEqual(request.codeIdentity, CodeIdentity.empty) requestExpectation.fulfill() do { - try self.rpcIssuer? + return try self.rpcIssuer .respond( serverErrorMessage: "INVALID_RECAPTCHA_TOKEN", error: AuthErrorUtils.invalidRecaptchaTokenError() as NSError ) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } do { @@ -573,12 +575,13 @@ verifyClientRequestExpectation.fulfill() do { // Response for the underlying VerifyClientRequest RPC call. - try self.rpcIssuer?.respond(withJSON: [ + return try self.rpcIssuer.respond(withJSON: [ "receipt": self.kTestReceipt, "suggestedTimeout": self.kTestTimeout, ]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } @@ -598,15 +601,18 @@ do { if visited == false || goodRetry == false { // First Response for the underlying SendVerificationCode RPC call. - try self.rpcIssuer?.respond(serverErrorMessage: "INVALID_APP_CREDENTIAL") + let (data, error) = try self.rpcIssuer + .respond(serverErrorMessage: "INVALID_APP_CREDENTIAL") visited = true + return (data, error) } else { // Second Response for the underlying SendVerificationCode RPC call. - try self.rpcIssuer? + return try self.rpcIssuer .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) } } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } @@ -662,29 +668,29 @@ verifyClientRequestExpectation.fulfill() do { // Response for the underlying VerifyClientRequest RPC call. - try self.rpcIssuer?.respond(withJSON: [ + return try self.rpcIssuer.respond(withJSON: [ "receipt": self.kTestReceipt, "suggestedTimeout": self.kTestTimeout, ]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } if reCAPTCHAfallback { let projectConfigExpectation = self.expectation(description: "projectConfiguration") - rpcIssuer?.projectConfigRequester = { request in + rpcIssuer.projectConfigRequester = { request in XCTAssertEqual(request.apiKey, PhoneAuthProviderTests.kFakeAPIKey) projectConfigExpectation.fulfill() - kAuthGlobalWorkQueue.async { - do { - // Response for the underlying VerifyClientRequest RPC call. - try self.rpcIssuer?.respond( - withJSON: ["projectId": "kFakeProjectID", - "authorizedDomains": [PhoneAuthProviderTests.kFakeAuthorizedDomain]] - ) - } catch { - XCTFail("Failure sending response: \(error)") - } + do { + // Response for the underlying VerifyClientRequest RPC call. + return try self.rpcIssuer.respond( + withJSON: ["projectId": "kFakeProjectID", + "authorizedDomains": [PhoneAuthProviderTests.kFakeAuthorizedDomain]] + ) + } catch { + XCTFail("Failure sending response: \(error)") + return (nil, nil) } } } @@ -711,10 +717,11 @@ verifyRequesterExpectation.fulfill() do { // Response for the underlying SendVerificationCode RPC call. - try self.rpcIssuer? + return try self.rpcIssuer .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } @@ -771,17 +778,18 @@ // 1. Intercept, handle, and test the projectConfiguration RPC calls. let projectConfigExpectation = expectation(description: "projectConfiguration") expectations.append(projectConfigExpectation) - rpcIssuer?.projectConfigRequester = { request in + rpcIssuer.projectConfigRequester = { request in XCTAssertEqual(request.apiKey, PhoneAuthProviderTests.kFakeAPIKey) projectConfigExpectation.fulfill() do { // Response for the underlying VerifyClientRequest RPC call. - try self.rpcIssuer?.respond( + return try self.rpcIssuer.respond( withJSON: ["projectId": "kFakeProjectID", "authorizedDomains": [PhoneAuthProviderTests.kFakeAuthorizedDomain]] ) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } } @@ -802,7 +810,7 @@ if errorURLString == nil, presenterError == nil { let requestExpectation = expectation(description: "verifyRequester") expectations.append(requestExpectation) - rpcIssuer?.verifyRequester = { request in + rpcIssuer.verifyRequester = { request in XCTAssertEqual(request.phoneNumber, self.kTestPhoneNumber) switch request.codeIdentity { case let .credential(credential): @@ -819,13 +827,14 @@ do { // Response for the underlying SendVerificationCode RPC call. if let errorString { - try self.rpcIssuer?.respond(serverErrorMessage: errorString) + return try self.rpcIssuer.respond(serverErrorMessage: errorString) } else { - try self.rpcIssuer? + return try self.rpcIssuer .respond(withJSON: [self.kVerificationIDKey: self.kTestVerificationID]) } } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } } diff --git a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift index 8ff45d7d073..f3ba6cb6cfb 100644 --- a/FirebaseAuth/Tests/Unit/RPCBaseTests.swift +++ b/FirebaseAuth/Tests/Unit/RPCBaseTests.swift @@ -99,7 +99,7 @@ class RPCBaseTests: XCTestCase { XCTFail("decodedRequest is not a dictionary") } // Dummy response to unblock await. - let _ = try self.rpcIssuer?.respond(withJSON: [:]) + return try self.rpcIssuer.respond(withJSON: [:]) } let _ = try await authBackend.call(with: request) } @@ -117,11 +117,11 @@ class RPCBaseTests: XCTestCase { checkLocalizedDescription: String? = nil) async throws { rpcIssuer.respondBlock = { if let json = json { - _ = try self.rpcIssuer.respond(withJSON: json) + return try self.rpcIssuer.respond(withJSON: json) } else if let reason = reason { - _ = try self.rpcIssuer.respond(underlyingErrorMessage: reason, message: message) + return try self.rpcIssuer.respond(underlyingErrorMessage: reason, message: message) } else { - _ = try self.rpcIssuer.respond(serverErrorMessage: message) + return try self.rpcIssuer.respond(serverErrorMessage: message) } } do { diff --git a/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift b/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift index a3220f3ee41..bb28a9cfa1d 100644 --- a/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift +++ b/FirebaseAuth/Tests/Unit/ResetPasswordTests.swift @@ -79,8 +79,8 @@ class ResetPasswordTests: RPCBaseTests { let kExpectedResetPasswordRequestType = "PASSWORD_RESET" rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["email": kTestEmail, - "requestType": kExpectedResetPasswordRequestType]) + try self.rpcIssuer.respond(withJSON: ["email": kTestEmail, + "requestType": kExpectedResetPasswordRequestType]) } let rpcResponse = try await authBackend.call(with: makeResetPasswordRequest()) diff --git a/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift b/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift index f55f42514d7..8fab2237e43 100644 --- a/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift +++ b/FirebaseAuth/Tests/Unit/RevokeTokenTests.swift @@ -51,7 +51,7 @@ class RevokeTokenTests: RPCBaseTests { */ func testSuccessfulRevokeTokenResponse() async throws { rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [:]) + try self.rpcIssuer.respond(withJSON: [:]) } let rpcResponse = try await authBackend.call(with: makeRevokeTokenRequest()) XCTAssertNotNil(rpcResponse) diff --git a/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift b/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift index d6b4b42bc14..e92bdf40f2b 100644 --- a/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift +++ b/FirebaseAuth/Tests/Unit/SendVerificationCodeTests.swift @@ -111,7 +111,7 @@ class SendVerificationCodeTests: RPCBaseTests { let kFakeVerificationID = "testVerificationID" rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [kVerificationIDKey: kFakeVerificationID]) + try self.rpcIssuer.respond(withJSON: [kVerificationIDKey: kFakeVerificationID]) } let rpcResponse = try await authBackend.call(with: makeSendVerificationCodeRequest(CodeIdentity.recaptcha(kTestReCAPTCHAToken))) diff --git a/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift b/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift index 037116982de..b3ccb3e8ad1 100644 --- a/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift +++ b/FirebaseAuth/Tests/Unit/SetAccountInfoTests.swift @@ -206,7 +206,7 @@ class SetAccountInfoTests: RPCBaseTests { let kTestRefreshToken = "REFRESH_TOKEN" rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: + try self.rpcIssuer.respond(withJSON: [kProviderUserInfoKey: [[kPhotoUrlKey: kTestPhotoURL]], kIDTokenKey: kTestIDToken, kExpiresInKey: kTestExpiresIn, diff --git a/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift b/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift index 515cbd13e87..989e436c575 100644 --- a/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift +++ b/FirebaseAuth/Tests/Unit/SignInWithGameCenterTests.swift @@ -87,7 +87,7 @@ class SignInWithGameCenterTests: RPCBaseTests { XCTAssertEqual(requestDictionary[kDisplayNameKey], kDisplayName) rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ "idToken": self.kIDToken, "refreshToken": kRefreshToken, "localId": kLocalID, diff --git a/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift b/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift index a75f6263a79..01c76eaf190 100644 --- a/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift +++ b/FirebaseAuth/Tests/Unit/SignUpNewUserTests.swift @@ -76,7 +76,7 @@ class SignUpNewUserTests: RPCBaseTests { let kRefreshTokenKey = "refreshToken" rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ kIDTokenKey: kTestIDToken, kExpiresInKey: kTestExpiresIn, kRefreshTokenKey: kTestRefreshToken, diff --git a/FirebaseAuth/Tests/Unit/UserTests.swift b/FirebaseAuth/Tests/Unit/UserTests.swift index d1f305f7116..ba11eb2ee47 100644 --- a/FirebaseAuth/Tests/Unit/UserTests.swift +++ b/FirebaseAuth/Tests/Unit/UserTests.swift @@ -411,7 +411,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "INVALID_EMAIL") + try self.rpcIssuer.respond(serverErrorMessage: "INVALID_EMAIL") } user.updateEmail(to: self.kNewEmail) { rawError in XCTAssertTrue(Thread.isMainThread) @@ -437,7 +437,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "INVALID_ID_TOKEN") + try self.rpcIssuer.respond(serverErrorMessage: "INVALID_ID_TOKEN") } user.updateEmail(to: self.kNewEmail) { rawError in XCTAssertTrue(Thread.isMainThread) @@ -466,8 +466,8 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } self.expectVerifyPhoneNumberRequest() self.rpcIssuer?.fakeGetAccountProviderJSON = [[ @@ -500,7 +500,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "INVALID_PHONE_NUMBER") + try self.rpcIssuer.respond(serverErrorMessage: "INVALID_PHONE_NUMBER") } self.expectVerifyPhoneNumberRequest() @@ -532,7 +532,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "TOKEN_EXPIRED") + try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED") } self.expectVerifyPhoneNumberRequest() @@ -575,7 +575,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN") + try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN") } user.updatePassword(to: self.kNewPassword) { rawError in XCTAssertTrue(Thread.isMainThread) @@ -601,7 +601,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "WEAK_PASSWORD") + try self.rpcIssuer.respond(serverErrorMessage: "WEAK_PASSWORD") } user.updatePassword(to: self.kNewPassword) { rawError in XCTAssertTrue(Thread.isMainThread) @@ -628,7 +628,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "USER_DISABLED") + try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED") } user.updatePassword(to: self.kNewPassword) { rawError in XCTAssertTrue(Thread.isMainThread) @@ -654,8 +654,8 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } let profileChange = user.createProfileChangeRequest() profileChange.photoURL = URL(string: self.kTestPhotoURL) @@ -681,7 +681,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER") + try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER") } let profileChange = user.createProfileChangeRequest() profileChange.displayName = self.kNewDisplayName @@ -710,7 +710,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "USER_NOT_FOUND") + try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND") } let profileChange = user.createProfileChangeRequest() profileChange.displayName = self.kNewDisplayName @@ -816,7 +816,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "QUOTA_EXCEEDED") + try self.rpcIssuer.respond(serverErrorMessage: "QUOTA_EXCEEDED") } // Clear fake so we can inject error self.rpcIssuer?.fakeGetAccountProviderJSON = nil @@ -843,7 +843,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "TOKEN_EXPIRED") + try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED") } // Clear fake so we can inject error self.rpcIssuer?.fakeGetAccountProviderJSON = nil @@ -870,8 +870,8 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, password: self.kFakePassword) @@ -899,14 +899,14 @@ class UserTests: RPCBaseTests { signInWithGoogleCredential { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken, accessToken: self.kGoogleAccessToken) @@ -950,8 +950,8 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } self.setFakeGetAccountProvider(withLocalID: "A different Local ID") let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, @@ -981,7 +981,7 @@ class UserTests: RPCBaseTests { signInWithEmailPasswordReturnFakeUser { user in do { self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "USER_NOT_FOUND") + try self.rpcIssuer.respond(serverErrorMessage: "USER_NOT_FOUND") } let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken, accessToken: self.kGoogleAccessToken) @@ -1012,14 +1012,14 @@ class UserTests: RPCBaseTests { do { self.setFakeGoogleGetAccountProvider() self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kGoogleID, - "providerId": GoogleAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kGoogleDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kGoogleID, + "providerId": GoogleAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kGoogleDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken, accessToken: self.kGoogleAccessToken) @@ -1062,7 +1062,7 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider() self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN") + try self.rpcIssuer.respond(serverErrorMessage: "CREDENTIAL_TOO_OLD_LOGIN_AGAIN") } let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken, accessToken: self.kGoogleAccessToken) @@ -1125,7 +1125,7 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider() self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "USER_DISABLED") + try self.rpcIssuer.respond(serverErrorMessage: "USER_DISABLED") } let googleCredential = GoogleAuthProvider.credential(withIDToken: self.kGoogleIDToken, accessToken: self.kGoogleAccessToken) @@ -1160,9 +1160,12 @@ class UserTests: RPCBaseTests { XCTAssertEqual(request?.email, self.kEmail) XCTAssertEqual(request?.password, self.kFakePassword) XCTAssertNil(request?.displayName) - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + let (data, error) = try self.rpcIssuer.respond(withJSON: [ + "idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + ]) self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id) + return (data, error) } let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, password: self.kFakePassword) @@ -1200,9 +1203,12 @@ class UserTests: RPCBaseTests { XCTAssertNotNil(request) XCTAssertEqual(request?.email, self.kEmail) XCTAssertEqual(request?.password, self.kFakePassword) - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + let (data, error) = try self.rpcIssuer.respond(withJSON: [ + "idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + ]) self.setFakeGetAccountProvider(withProviderID: EmailAuthProvider.id) + return (data, error) } let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, password: self.kFakePassword) @@ -1242,7 +1248,7 @@ class UserTests: RPCBaseTests { XCTAssertNotNil(request) XCTAssertEqual(request?.email, self.kEmail) XCTAssertEqual(request?.password, self.kFakePassword) - try self.rpcIssuer?.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER") + return try self.rpcIssuer.respond(serverErrorMessage: "TOO_MANY_ATTEMPTS_TRY_LATER") } let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, password: self.kFakePassword) @@ -1272,7 +1278,7 @@ class UserTests: RPCBaseTests { do { self.rpcIssuer.respondBlock = { XCTAssertNotNil(self.rpcIssuer?.request as? SignUpNewUserRequest) - try self.rpcIssuer?.respond(serverErrorMessage: "TOKEN_EXPIRED") + return try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED") } let emailCredential = EmailAuthProvider.credential(withEmail: self.kEmail, password: self.kFakePassword) @@ -1292,16 +1298,12 @@ class UserTests: RPCBaseTests { #if os(iOS) private class FakeOAuthProvider: OAuthProvider { - override func getCredentialWith(_ UIDelegate: AuthUIDelegate?, - completion: ((AuthCredential?, Error?) -> Void)? = nil) { - if let completion { - let credential = OAuthCredential( - withProviderID: GoogleAuthProvider.id, - sessionID: UserTests.kOAuthSessionID, - OAuthResponseURLString: UserTests.kOAuthRequestURI - ) - completion(credential, nil) - } + override func credential(with uiDelegate: AuthUIDelegate?) async throws -> AuthCredential { + return OAuthCredential( + withProviderID: GoogleAuthProvider.id, + sessionID: UserTests.kOAuthSessionID, + OAuthResponseURLString: UserTests.kOAuthRequestURI + ) } } @@ -1318,7 +1320,7 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider() self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "TOKEN_EXPIRED") + try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED") } user.link(with: FakeOAuthProvider(providerID: "foo", auth: auth), uiDelegate: nil) { linkAuthResult, rawError in @@ -1347,7 +1349,7 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider() self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(serverErrorMessage: "TOKEN_EXPIRED") + try self.rpcIssuer.respond(serverErrorMessage: "TOKEN_EXPIRED") } user.reauthenticate(with: FakeOAuthProvider(providerID: "foo", auth: auth), uiDelegate: nil) { linkAuthResult, rawError in @@ -1377,8 +1379,8 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id) self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } let credential = PhoneAuthProvider.provider(auth: auth).credential( withVerificationID: self.kVerificationID, @@ -1422,8 +1424,8 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id) self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } let credential = PhoneAuthProvider.provider(auth: auth).credential( withVerificationID: self.kVerificationID, @@ -1460,8 +1462,8 @@ class UserTests: RPCBaseTests { XCTAssertNil(request.providers) XCTAssertNil(request.deleteAttributes) XCTAssertEqual(try XCTUnwrap(request.deleteProviders?.first), PhoneAuthProvider.id) - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken]) } user.unlink(fromProvider: PhoneAuthProvider.id) { user, error in XCTAssertNil(error) @@ -1518,10 +1520,10 @@ class UserTests: RPCBaseTests { do { self.setFakeGetAccountProvider(withProviderID: PhoneAuthProvider.id) self.rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "phoneNumber": self.kTestPhoneNumber, - "temporaryProof": "Fake Temporary Proof"]) + try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "phoneNumber": self.kTestPhoneNumber, + "temporaryProof": "Fake Temporary Proof"]) } let credential = PhoneAuthProvider.provider(auth: auth).credential( withVerificationID: self.kVerificationID, @@ -1627,9 +1629,9 @@ class UserTests: RPCBaseTests { XCTAssertNil(request.deleteAttributes) XCTAssertNil(request.deleteProviders) - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "email": self.kNewEmail, - "refreshToken": self.kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "email": self.kNewEmail, + "refreshToken": self.kRefreshToken]) } if changeEmail { user.updateEmail(to: kNewEmail) { error in @@ -1664,11 +1666,12 @@ class UserTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) do { // 3. Send the response from the fake backend. - try self.rpcIssuer?.respond(withJSON: ["idToken": fakeAccessToken, - "isNewUser": true, - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": fakeAccessToken, + "isNewUser": true, + "refreshToken": kRefreshToken]) } catch { XCTFail("Failure sending response: \(error)") + return (nil, nil) } } // 1. After setting up fakes, sign out and sign in. @@ -1711,13 +1714,13 @@ class UserTests: RPCBaseTests { ) // 3. Send the response from the fake backend. - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "providerId": GoogleAuthProvider.id, - "refreshToken": self.kRefreshToken, - "localId": self.kLocalID, - "displayName": self.kDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "providerId": GoogleAuthProvider.id, + "refreshToken": self.kRefreshToken, + "localId": self.kLocalID, + "displayName": self.kDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } do { @@ -1777,14 +1780,14 @@ class UserTests: RPCBaseTests { XCTAssertTrue(request.returnSecureToken) // 3. Send the response from the fake backend. - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "refreshToken": self.kRefreshToken, - "federatedId": self.kFacebookID, - "providerId": FacebookAuthProvider.id, - "localId": self.kLocalID, - "displayName": self.kDisplayName, - "rawUserInfo": self.kGoogleProfile, - "username": self.kUserName]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "federatedId": self.kFacebookID, + "providerId": FacebookAuthProvider.id, + "localId": self.kLocalID, + "displayName": self.kDisplayName, + "rawUserInfo": self.kGoogleProfile, + "username": self.kUserName]) } do { @@ -1837,9 +1840,9 @@ class UserTests: RPCBaseTests { XCTAssertNil(request.idToken) // Send the response from the fake backend. - try self.rpcIssuer?.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, - "isNewUser": true, - "refreshToken": kRefreshToken]) + return try self.rpcIssuer.respond(withJSON: ["idToken": RPCBaseTests.kFakeAccessToken, + "isNewUser": true, + "refreshToken": kRefreshToken]) } do { diff --git a/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift b/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift index 2fb630a62ce..c8b58bcd60a 100644 --- a/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyAssertionTests.swift @@ -168,7 +168,7 @@ class VerifyAssertionTests: RPCBaseTests { */ func testSuccessfulVerifyAssertionResponse() async throws { rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ self.kProviderIDKey: self.kTestProviderID, self.kIDTokenKey: self.kTestIDToken, self.kExpiresInKey: self.kTestExpiresIn, @@ -199,7 +199,7 @@ class VerifyAssertionTests: RPCBaseTests { */ func testSuccessfulVerifyAssertionResponseWithTextData() async throws { rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ self.kProviderIDKey: self.kTestProviderID, self.kIDTokenKey: self.kTestIDToken, self.kExpiresInKey: self.kTestExpiresIn, diff --git a/FirebaseAuth/Tests/Unit/VerifyClientTests.swift b/FirebaseAuth/Tests/Unit/VerifyClientTests.swift index 528cb357c88..e501069633c 100644 --- a/FirebaseAuth/Tests/Unit/VerifyClientTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyClientTests.swift @@ -66,7 +66,7 @@ class VerifyClientTests: RPCBaseTests { let kFakeSuggestedTimeout = "1234" rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ kReceiptKey: kFakeReceipt, kSuggestedTimeOutKey: kFakeSuggestedTimeout, ]) diff --git a/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift b/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift index 8e3e052a4b2..a40e00a51b5 100644 --- a/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyCustomTokenTests.swift @@ -100,7 +100,7 @@ class VerifyCustomTokenTests: RPCBaseTests { let kIsNewUserKey = "isNewUser" rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ kIDTokenKey: kTestIDToken, kExpiresInKey: kTestExpiresIn, kRefreshTokenKey: kTestRefreshToken, diff --git a/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift b/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift index 06821bf74c2..9f93d86daac 100644 --- a/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyPasswordTests.swift @@ -161,7 +161,7 @@ class VerifyPasswordTests: RPCBaseTests { let kTestPhotoUrl = "www.example.com" rpcIssuer?.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ kLocalIDKey: kTestLocalID, kEmailKey: kTestEmail, kDisplayNameKey: kTestDisplayName, diff --git a/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift b/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift index 50fb9cf67e5..10831736a50 100644 --- a/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift +++ b/FirebaseAuth/Tests/Unit/VerifyPhoneNumberTests.swift @@ -108,7 +108,7 @@ import XCTest let kTestRefreshToken = "REFRESH_TOKEN" rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ "idToken": kTestIDToken, "refreshToken": kTestRefreshToken, "localId": kTestLocalID, @@ -129,7 +129,7 @@ import XCTest */ func testSuccessfulVerifyPhoneNumberResponseWithTemporaryProof() async throws { rpcIssuer.respondBlock = { - try self.rpcIssuer?.respond(withJSON: [ + try self.rpcIssuer.respond(withJSON: [ "temporaryProof": self.kTemporaryProof, "phoneNumber": self.kPhoneNumber, ]) From 44ab3a9846ce7262b57efb739603a95582afcfdb Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 10 Dec 2024 07:35:18 -0800 Subject: [PATCH 79/98] [auth] Fix Multi-factor session crash on second Firebase app (#14238) Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- FirebaseAuth/CHANGELOG.md | 1 + FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift | 2 +- .../Sources/Swift/MultiFactor/MultiFactorSession.swift | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 9a878b35ca7..8940131c5c3 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,5 @@ # Unreleased +- [fixed] Fix Multi-factor session crash on second Firebase app. (#14238) - [fixed] Updated most decoders to be consistent with Firebase 10's behavior for decoding `nil` values. (#14212) diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift index c60f353e362..5b1675fdfa0 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift @@ -34,7 +34,7 @@ import Foundation /// operation. @objc(getSessionWithCompletion:) open func getSessionWithCompletion(_ completion: ((MultiFactorSession?, Error?) -> Void)?) { - let session = MultiFactorSession.sessionForCurrentUser + let session = MultiFactorSession.session(for: user) if let completion { completion(session, nil) } diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift index 42067fd30c3..c4bda3eba36 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift @@ -39,8 +39,9 @@ import Foundation /// Current user object. var currentUser: User? - class var sessionForCurrentUser: MultiFactorSession { - guard let currentUser = Auth.auth().currentUser else { + class func session(for user: User?) -> MultiFactorSession { + let currentUser = user ?? Auth.auth().currentUser + guard let currentUser else { fatalError("Internal Auth Error: missing user for multifactor auth") } return .init(idToken: currentUser.tokenService.accessToken, currentUser: currentUser) From e0eaaea7dd8ff0b884e871c78150d0ca97d5f92a Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Tue, 10 Dec 2024 13:33:53 -0800 Subject: [PATCH 80/98] AuthNotificationManager from continuation to AsyncStream (#14232) --- .../AuthNotificationManager.swift | 96 ++++++++----------- .../Swift/Utilities/AuthCondition.swift | 40 ++++++++ .../Unit/AuthNotificationManagerTests.swift | 16 ++-- 3 files changed, 89 insertions(+), 63 deletions(-) create mode 100644 FirebaseAuth/Sources/Swift/Utilities/AuthCondition.swift diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift index 296ab5d4b28..1dbb6c9c435 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift @@ -56,8 +56,7 @@ /// Only tests should access this property. var immediateCallbackForTestFaking: (() -> Bool)? - /// All pending callbacks while a check is being performed. - private var pendingCallbacks: [(Bool) -> Void]? + private let condition: AuthCondition /// Initializes the instance. /// - Parameter application: The application. @@ -69,56 +68,53 @@ self.application = application self.appCredentialManager = appCredentialManager timeout = kProbingTimeout + condition = AuthCondition() } - /// Checks whether or not remote notifications are being forwarded to this class. - /// - Parameter callback: The block to be called either immediately or in future once a result - /// is available. - func checkNotificationForwardingInternal(withCallback callback: @escaping (Bool) -> Void) { - if pendingCallbacks != nil { - pendingCallbacks?.append(callback) - return + private actor PendingCount { + private var count = 0 + func increment() -> Int { + count = count + 1 + return count } + } + + private let pendingCount = PendingCount() + + /// Checks whether or not remote notifications are being forwarded to this class. + func checkNotificationForwarding() async -> Bool { if let getValueFunc = immediateCallbackForTestFaking { - callback(getValueFunc()) - return + return getValueFunc() } if hasCheckedNotificationForwarding { - callback(isNotificationBeingForwarded) - return + return isNotificationBeingForwarded } - hasCheckedNotificationForwarding = true - pendingCallbacks = [callback] - - DispatchQueue.main.async { - let proberNotification = [self.kNotificationDataKey: [self.kNotificationProberKey: - "This fake notification should be forwarded to Firebase Auth."]] - if let delegate = self.application.delegate, - delegate - .responds(to: #selector(UIApplicationDelegate - .application(_:didReceiveRemoteNotification:fetchCompletionHandler:))) { - delegate.application?(self.application, - didReceiveRemoteNotification: proberNotification) { _ in + if await pendingCount.increment() == 1 { + DispatchQueue.main.async { + let proberNotification = [self.kNotificationDataKey: [self.kNotificationProberKey: + "This fake notification should be forwarded to Firebase Auth."]] + if let delegate = self.application.delegate, + delegate + .responds(to: #selector(UIApplicationDelegate + .application(_:didReceiveRemoteNotification:fetchCompletionHandler:))) { + delegate.application?(self.application, + didReceiveRemoteNotification: proberNotification) { _ in + } + } else { + AuthLog.logWarning( + code: "I-AUT000015", + message: "The UIApplicationDelegate must handle " + + "remote notification for phone number authentication to work." + ) + } + kAuthGlobalWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(self.timeout))) { + self.condition.signal() } - } else { - AuthLog.logWarning( - code: "I-AUT000015", - message: "The UIApplicationDelegate must handle " + - "remote notification for phone number authentication to work." - ) - } - kAuthGlobalWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(self.timeout))) { - self.callback() - } - } - } - - func checkNotificationForwarding() async -> Bool { - return await withUnsafeContinuation { continuation in - checkNotificationForwardingInternal { value in - continuation.resume(returning: value) } } + await condition.wait() + hasCheckedNotificationForwarding = true + return isNotificationBeingForwarded } /// Attempts to handle the remote notification. @@ -140,12 +136,12 @@ return false } if dictionary[kNotificationProberKey] != nil { - if pendingCallbacks == nil { + if hasCheckedNotificationForwarding { // The prober notification probably comes from another instance, so pass it along. return false } isNotificationBeingForwarded = true - callback() + condition.signal() return true } guard let receipt = dictionary[kNotificationReceiptKey] as? String, @@ -154,17 +150,5 @@ } return appCredentialManager.canFinishVerification(withReceipt: receipt, secret: secret) } - - // MARK: Internal methods - - private func callback() { - guard let pendingCallbacks else { - return - } - self.pendingCallbacks = nil - for callback in pendingCallbacks { - callback(isNotificationBeingForwarded) - } - } } #endif diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthCondition.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthCondition.swift new file mode 100644 index 00000000000..da8c9c1639b --- /dev/null +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthCondition.swift @@ -0,0 +1,40 @@ +// Copyright 2024 Google LLC +// +// 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 + +/// Utility struct to make the execution of one task dependent upon a signal from another task. +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +struct AuthCondition { + private let waiter: () async -> Void + private let stream: AsyncStream.Continuation + + init() { + let (stream, continuation) = AsyncStream.makeStream() + waiter = { + for await _ in stream {} + } + self.stream = continuation + } + + // Signal to unblock the waiter. + func signal() { + stream.finish() + } + + /// Wait for the condition. + func wait() async { + await waiter() + } +} diff --git a/FirebaseAuth/Tests/Unit/AuthNotificationManagerTests.swift b/FirebaseAuth/Tests/Unit/AuthNotificationManagerTests.swift index a30399e3d00..ec438e85b41 100644 --- a/FirebaseAuth/Tests/Unit/AuthNotificationManagerTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthNotificationManagerTests.swift @@ -33,7 +33,7 @@ /** @property notificationManager @brief The notification manager to forward. */ - private var notificationManager: AuthNotificationManager? + private var notificationManager: AuthNotificationManager! /** @var modernDelegate @brief The modern fake UIApplicationDelegate for testing. @@ -75,7 +75,8 @@ private func verify(forwarding: Bool, delegate: FakeForwardingDelegate) throws { delegate.forwardsNotification = forwarding let expectation = self.expectation(description: "callback") - notificationManager?.checkNotificationForwardingInternal { forwarded in + Task { + let forwarded = await notificationManager.checkNotificationForwarding() XCTAssertEqual(forwarded, forwarding) expectation.fulfill() } @@ -93,12 +94,13 @@ let delegate = try XCTUnwrap(modernDelegate) try verify(forwarding: false, delegate: delegate) modernDelegate?.notificationReceived = false - var calledBack = false - notificationManager?.checkNotificationForwardingInternal { isNotificationBeingForwarded in + let expectation = self.expectation(description: "callback") + Task { + let isNotificationBeingForwarded = await notificationManager.checkNotificationForwarding() XCTAssertFalse(isNotificationBeingForwarded) - calledBack = true + expectation.fulfill() } - XCTAssertTrue(calledBack) + waitForExpectations(timeout: 5) XCTAssertFalse(delegate.notificationReceived) } @@ -136,7 +138,7 @@ .canHandle(notification: ["com.google.firebase.auth": ["secret": kSecret]])) // Probing notification does not belong to this instance. XCTAssertFalse(manager - .canHandle(notification: ["com.google.firebase.auth": ["warning": "asdf"]])) + .canHandle(notification: ["com.google.firebase.auth": ["error": "asdf"]])) } private class FakeApplication: UIApplication {} From 01dc42078a9ca513c0d6fc32dcdf7300e6bb5923 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:23:57 -0500 Subject: [PATCH 81/98] [Firestore] Label '@MainActor' isolated APIs of 'FirestoreQuery' (#14163) --- Firestore/Swift/Source/PropertyWrapper/FirestoreQuery.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firestore/Swift/Source/PropertyWrapper/FirestoreQuery.swift b/Firestore/Swift/Source/PropertyWrapper/FirestoreQuery.swift index de3716856bc..ff78b68e509 100644 --- a/Firestore/Swift/Source/PropertyWrapper/FirestoreQuery.swift +++ b/Firestore/Swift/Source/PropertyWrapper/FirestoreQuery.swift @@ -143,12 +143,12 @@ public struct FirestoreQuery: DynamicProperty { /// The results of the query. /// /// This property returns an empty collection when there are no matching results. - public var wrappedValue: T { + @MainActor @preconcurrency public var wrappedValue: T { firestoreQueryObservable.items } /// A binding to the request's mutable configuration properties - public var projectedValue: Configuration { + @MainActor @preconcurrency public var projectedValue: Configuration { get { firestoreQueryObservable.configuration } From b372ee7f1256a0b897c471eb3b9e94bf11f96c84 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Wed, 11 Dec 2024 12:12:49 -0800 Subject: [PATCH 82/98] [rc] Mark ConfigUpdateListenerRegistration Sendable (#14244) --- FirebaseRemoteConfig/CHANGELOG.md | 3 +++ .../Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h | 1 + 2 files changed, 4 insertions(+) diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index 62047c8e55b..063c96be63d 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Mark ConfigUpdateListenerRegistration Sendable. (#14215) + # 11.5.0 - [fixed] Mark two internal properties as `atomic` to prevent concurrency related crash. (#13898) diff --git a/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h b/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h index 0a45617545f..76b4f6fc690 100644 --- a/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h +++ b/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h @@ -38,6 +38,7 @@ extern NSString *const _Nonnull FIRRemoteConfigThrottledEndTimeInSecondsKey NS_S * RC backend is closed. Subsequently calling `addOnConfigUpdateListener` will re-open the * connection. */ +NS_SWIFT_SENDABLE NS_SWIFT_NAME(ConfigUpdateListenerRegistration) @interface FIRConfigUpdateListenerRegistration : NSObject /** From 326993cc9257043aaed08fd3b53f0980b3ee8f49 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:38:55 -0500 Subject: [PATCH 83/98] [Auth] Convert LoginView to SwiftUI (#13628) --- .../project.pbxproj | 20 +- .../AuthenticationExample/AppDelegate.swift | 4 + .../Assets.xcassets/Contents.json | 6 +- .../firebaseLogo.imageset/Contents.json | 21 -- .../firebaseLogo.imageset/logo-1024px.png | Bin 419995 -> 0 bytes .../CustomViews/LoginView.swift | 282 +++++++++--------- .../Utility/Extensions.swift | 1 + .../ViewControllers/AuthViewController.swift | 179 +++-------- .../ViewControllers/LoginController.swift | 139 --------- 9 files changed, 208 insertions(+), 444 deletions(-) delete mode 100644 FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/Contents.json delete mode 100644 FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/logo-1024px.png delete mode 100644 FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj index feb55512ba4..f6a45f1b931 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample.xcodeproj/project.pbxproj @@ -46,6 +46,7 @@ EA20B50C249E8F0700B5E581 /* AuthMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA20B50B249E8F0700B5E581 /* AuthMenu.swift */; }; EA20B510249FDB4400B5E581 /* OtherAuthMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA20B50F249FDB4400B5E581 /* OtherAuthMethods.swift */; }; EA217895248979E200736757 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EA217894248979E200736757 /* LaunchScreen.storyboard */; }; + EA3348322C90EFF40091D7C2 /* LoginViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3348312C90EFE40091D7C2 /* LoginViewSwiftUI.swift */; }; EA527CAA24A0766D00ADB9A2 /* OtherAuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA527CA924A0766D00ADB9A2 /* OtherAuthViewController.swift */; }; EA527CAC24A0EE9600ADB9A2 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */; }; EAB3A1792494433500385291 /* DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB3A1782494433500385291 /* DataSourceProvider.swift */; }; @@ -57,7 +58,6 @@ EAE4CBC924855E3A00245E92 /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4CBC824855E3A00245E92 /* AuthViewController.swift */; }; EAE4CBCE24855E3D00245E92 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAE4CBCD24855E3D00245E92 /* Assets.xcassets */; }; EAE4CBE724855E3E00245E92 /* AuthenticationExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4CBE624855E3E00245E92 /* AuthenticationExampleUITests.swift */; }; - EAE4CBF524857A5100245E92 /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4CBF424857A5100245E92 /* LoginController.swift */; }; EAEBCE0F2489FFDE00FCEA92 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEBCE0E2489FFDE00FCEA92 /* Extensions.swift */; }; EAEBCE11248A9AA000FCEA92 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEBCE10248A9AA000FCEA92 /* Section.swift */; }; EAFDF2BE2490439F0082B6F1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAFDF2BD2490439F0082B6F1 /* Animator.swift */; }; @@ -125,8 +125,8 @@ EA20B50B249E8F0700B5E581 /* AuthMenu.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AuthMenu.swift; sourceTree = ""; }; EA20B50F249FDB4400B5E581 /* OtherAuthMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherAuthMethods.swift; sourceTree = ""; }; EA217894248979E200736757 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + EA3348312C90EFE40091D7C2 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; EA527CA924A0766D00ADB9A2 /* OtherAuthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OtherAuthViewController.swift; sourceTree = ""; }; - EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; EAB3A1782494433500385291 /* DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceProvider.swift; sourceTree = ""; }; EAB3A17B2494628200385291 /* UserViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewController.swift; sourceTree = ""; }; EAD8BD3F2CE535C400E23E30 /* MFALoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFALoginView.swift; sourceTree = ""; }; @@ -140,7 +140,6 @@ EAE4CBE224855E3E00245E92 /* AuthenticationExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AuthenticationExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EAE4CBE624855E3E00245E92 /* AuthenticationExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationExampleUITests.swift; sourceTree = ""; }; EAE4CBE824855E3E00245E92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - EAE4CBF424857A5100245E92 /* LoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = ""; }; EAEBCE0E2489FFDE00FCEA92 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; EAEBCE10248A9AA000FCEA92 /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; EAFDF2BD2490439F0082B6F1 /* Animator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; @@ -224,7 +223,6 @@ children = ( EAE08EB424CF5D09006FA3A5 /* AccountLinkingViewController.swift */, EAE4CBC824855E3A00245E92 /* AuthViewController.swift */, - EAE4CBF424857A5100245E92 /* LoginController.swift */, EAB3A17B2494628200385291 /* UserViewController.swift */, EA02F68E24A0714B0079D000 /* OtherAuthMethodControllers */, DEC2E5DC2A95331D0090260A /* SettingsViewController.swift */, @@ -248,7 +246,7 @@ children = ( EAD8BD3F2CE535C400E23E30 /* MFALoginView.swift */, EA20B46B2495A9F900B5E581 /* SignedOutView.swift */, - EA527CAB24A0EE9600ADB9A2 /* LoginView.swift */, + EA3348312C90EFE40091D7C2 /* LoginView.swift */, ); path = CustomViews; sourceTree = ""; @@ -550,6 +548,7 @@ buildActionMask = 2147483647; files = ( EA20B46E2495B2C700B5E581 /* DataSourceProtocols.swift in Sources */, + EA3348322C90EFF40091D7C2 /* LoginView.swift in Sources */, EAB3A1792494433500385291 /* DataSourceProvider.swift in Sources */, EA20B46C2495A9F900B5E581 /* SignedOutView.swift in Sources */, EA527CAA24A0766D00ADB9A2 /* OtherAuthViewController.swift in Sources */, @@ -560,7 +559,6 @@ EA02F68524A000E00079D000 /* UserActions.swift in Sources */, EA02F68D24A063E90079D000 /* LoginDelegate.swift in Sources */, EA20B50A249D3D8600B5E581 /* PasswordlessViewController.swift in Sources */, - EAE4CBF524857A5100245E92 /* LoginController.swift in Sources */, EA20B510249FDB4400B5E581 /* OtherAuthMethods.swift in Sources */, EA12697F29E33A5D00D79E66 /* CryptoUtils.swift in Sources */, EAEBCE11248A9AA000FCEA92 /* Section.swift in Sources */, @@ -572,7 +570,6 @@ EAFDF2BE2490439F0082B6F1 /* Animator.swift in Sources */, EAE4CBC724855E3A00245E92 /* SceneDelegate.swift in Sources */, EAE08EB524CF5D09006FA3A5 /* AccountLinkingViewController.swift in Sources */, - EA527CAC24A0EE9600ADB9A2 /* LoginView.swift in Sources */, EAEBCE0F2489FFDE00FCEA92 /* Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -717,7 +714,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -772,7 +769,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_LDFLAGS = "-ObjC"; @@ -815,6 +812,7 @@ "CODE_SIGN_IDENTITY[sdk=*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = EQHXZ8M8AV; INFOPLIST_FILE = AuthenticationExample/SwiftApplication.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -839,7 +837,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = SwiftApiTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -864,7 +862,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = SwiftApiTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/AppDelegate.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/AppDelegate.swift index 12efe53800d..50a4e11d04b 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/AppDelegate.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/AppDelegate.swift @@ -71,5 +71,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func configureApplicationAppearance() { UINavigationBar.appearance().tintColor = .systemOrange UITabBar.appearance().tintColor = .systemOrange + // Handles iOS 15 behavior change where tab bar become translucent during transitions. + let appearance = UITabBarAppearance() + appearance.configureWithOpaqueBackground() + UITabBar.appearance().scrollEdgeAppearance = appearance } } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/Contents.json b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/Contents.json index da4a164c918..73c00596a7f 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/Contents.json +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/Contents.json b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/Contents.json deleted file mode 100644 index 4a7c90e06a3..00000000000 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "logo-1024px.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/logo-1024px.png b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Assets.xcassets/firebaseLogo.imageset/logo-1024px.png deleted file mode 100644 index 1bbdb22d593f6a46ef05948aa7efffa1466131da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 419995 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%0ATZ&(S0h?FEmB&vQHwI78TeDA)_ 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

~9bSD~{?nYqK=79JxARTi!?ynQ_vR!HaP{ew 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 TCSoN;d#itRdvp( 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 b5FjByLV$z-2>}uUBm_tZkP!I)g1~ Date: Fri, 27 Dec 2024 15:26:30 -0500 Subject: [PATCH 94/98] add explanation of how alloc works (#14288) --- .../Models/Record/FIRCLSReportAdapter.m | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m index 2cbcdb9ef23..900f93c20ee 100644 --- a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m +++ b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m @@ -256,6 +256,21 @@ - (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str { * @param data The data to copy into the new bytes array. */ pb_bytes_array_t *FIRCLSEncodeData(NSData *data) { + // We have received couple security tickets before for using malloc here. + // Here is a short explaination on how it is calculated so buffer overflow is prevented: + // We will alloc an amount of memeory for struct `pb_bytes_array_t`, this struct contains two + // attributes: + // pb_size_t size + // pb_byte_t bytes[1] + // It contains the size the of the data and the actually data information in byte form (which + // is represented by a pointer), for more information check the declaration in nanopb/pb.h. + + // For size, NSData return size in `unsigned long` type which is the same size as `pb_size_t` and + // it is declared in compile time depending on the arch of system. If overflow happened it should + // happend at NSData level first when user trying to inserting data to NSData. + // For bytes, it is just a strict memeory copy of the data in NSData. + // The whole structure will be freed as a part of process for deallocing report in dealloc() of + // this class pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); if (pbBytes == NULL) { return NULL; From 93bd88189ebd633ab7b905199d4a05d36fcc2dc7 Mon Sep 17 00:00:00 2001 From: themiswang Date: Fri, 27 Dec 2024 16:02:57 -0500 Subject: [PATCH 95/98] Change malloc to calloc (#14289) --- Crashlytics/CHANGELOG.md | 1 + Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m | 2 +- Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c | 6 +++--- Crashlytics/Crashlytics/Helpers/FIRCLSFile.m | 6 +++--- Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m | 2 +- Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m | 4 ++-- Crashlytics/Shared/FIRCLSByteUtility.m | 2 +- Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m | 2 +- Crashlytics/UnitTests/FIRCLSCompactUnwindTests.m | 2 +- Crashlytics/UnitTests/FIRCLSDwarfTests.m | 2 +- Crashlytics/UnitTests/FIRCLSFileTests.m | 4 ++-- Crashlytics/UnitTests/FIRCLSLoggingTests.m | 2 +- 12 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Crashlytics/CHANGELOG.md b/Crashlytics/CHANGELOG.md index 59058cf574c..598aed30656 100644 --- a/Crashlytics/CHANGELOG.md +++ b/Crashlytics/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased - [fixed] Updated `upload-symbols` to version 3.20, wait for `debug.dylib` DWARF content getting generated when build with `--build-phase` option. Added `debug.dylib` DWARF content to run script input file list for user who enabled user script sandboxing (#14054). +- [fixed] Updated all memory allocation from `malloc()` to `calloc()` (#14209). # 11.5.0 - [changed] Updated `upload-symbols` to version 3.19, removed all methods require CFRelease and switch to modern classes (#13420). diff --git a/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m b/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m index 35cb32b02fb..c7e1a602e83 100644 --- a/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m +++ b/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m @@ -409,7 +409,7 @@ static void FIRCLSBinaryImageChanged(bool added, // fill imageDetails fields using slice & vmaddr_slide FIRCLSBinaryImageFillInImageDetails(&imageDetails); - FIRCLSImageChange* change = malloc(sizeof(FIRCLSImageChange)); + FIRCLSImageChange* change = calloc(1, sizeof(FIRCLSImageChange)); if (!change) return; change->added = added; change->details = imageDetails; diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c b/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c index 206b9a4e80d..acf78d98496 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c @@ -175,7 +175,7 @@ void* FIRCLSAllocatorSafeAllocateFromRegion(FIRCLSAllocationRegion* region, size // this shouldn't happen unless we make a mistake with our size pre-computations if ((uintptr_t)originalCursor - (uintptr_t)region->start + size > region->size) { FIRCLSSDKLog("Unable to allocate sufficient memory, falling back to malloc\n"); - void* ptr = malloc(size); + void* ptr = calloc(1, size); if (!ptr) { FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocateFromRegion\n"); return NULL; @@ -197,7 +197,7 @@ void* FIRCLSAllocatorSafeAllocate(FIRCLSAllocatorRef allocator, if (!allocator) { // fall back to malloc in this case FIRCLSSDKLog("Allocator invalid, falling back to malloc\n"); - void* ptr = malloc(size); + void* ptr = calloc(1, size); if (!ptr) { FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); return NULL; @@ -207,7 +207,7 @@ void* FIRCLSAllocatorSafeAllocate(FIRCLSAllocatorRef allocator, if (allocator->protectionEnabled) { FIRCLSSDKLog("Allocator already protected, falling back to malloc\n"); - void* ptr = malloc(size); + void* ptr = calloc(1, size); if (!ptr) { FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); return NULL; diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m b/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m index 204782a633b..1f4d2a0c836 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m @@ -74,7 +74,7 @@ static bool FIRCLSFileInit( file->bufferWrites = bufferWrites; if (bufferWrites) { - file->writeBuffer = malloc(FIRCLSWriteBufferLength * sizeof(char)); + file->writeBuffer = calloc(1, FIRCLSWriteBufferLength * sizeof(char)); if (!file->writeBuffer) { FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileInit"); return false; @@ -668,7 +668,7 @@ void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* val NSString* FIRCLSFileHexEncodeString(const char* string) { size_t length = strlen(string); - char* encodedBuffer = malloc(length * 2 + 1); + char* encodedBuffer = calloc(1, length * 2 + 1); if (!encodedBuffer) { FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexEncodeString"); @@ -693,7 +693,7 @@ void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* val NSString* FIRCLSFileHexDecodeString(const char* string) { size_t length = strlen(string); - char* decodedBuffer = malloc(length); // too long, but safe + char* decodedBuffer = calloc(1, length); // too long, but safe if (!decodedBuffer) { FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexDecodeString"); return nil; diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m b/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m index 7592aa01424..21e87ac66fd 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m @@ -185,7 +185,7 @@ void FIRCLSRedactUUID(char* value) { // null terminator length = [data length]; size = (length * 2) + 1; - buffer = malloc(sizeof(char) * size); + buffer = calloc(1, sizeof(char) * size); if (!buffer) { FIRCLSErrorLog(@"Unable to malloc in FIRCLSNSDataToNSString"); diff --git a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m index 900f93c20ee..543c6bfc718 100644 --- a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m +++ b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m @@ -171,7 +171,7 @@ - (google_crashlytics_FilesPayload)protoFilesPayload { NSArray *clsRecords = [self clsRecordFilePaths]; google_crashlytics_FilesPayload_File *files = - malloc(sizeof(google_crashlytics_FilesPayload_File) * clsRecords.count); + calloc(1, sizeof(google_crashlytics_FilesPayload_File) * clsRecords.count); if (files == NULL) { // files and files_count are initialized to NULL and 0 by default. @@ -271,7 +271,7 @@ - (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str { // For bytes, it is just a strict memeory copy of the data in NSData. // The whole structure will be freed as a part of process for deallocing report in dealloc() of // this class - pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + pb_bytes_array_t *pbBytes = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); if (pbBytes == NULL) { return NULL; } diff --git a/Crashlytics/Shared/FIRCLSByteUtility.m b/Crashlytics/Shared/FIRCLSByteUtility.m index 8298bf1299c..f27d60be7a3 100644 --- a/Crashlytics/Shared/FIRCLSByteUtility.m +++ b/Crashlytics/Shared/FIRCLSByteUtility.m @@ -58,7 +58,7 @@ void FIRCLSSafeHexToString(const uint8_t *value, size_t length, char *outputBuff // null terminator length = data.length; size = (length * 2) + 1; - buffer = malloc(sizeof(char) * size); + buffer = calloc(1, sizeof(char) * size); if (!buffer) { return nil; diff --git a/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m b/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m index 02e9125af74..2b8b67915a3 100644 --- a/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m +++ b/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m @@ -144,7 +144,7 @@ static void FIRCLSSafeHexToString(const uint8_t* value, size_t length, char* out // null terminator length = [data length]; size = (length * 2) + 1; - buffer = malloc(sizeof(char) * size); + buffer = calloc(1, sizeof(char) * size); if (!buffer) { return nil; diff --git a/Crashlytics/UnitTests/FIRCLSCompactUnwindTests.m b/Crashlytics/UnitTests/FIRCLSCompactUnwindTests.m index 204911949b2..fc5bcabf73a 100644 --- a/Crashlytics/UnitTests/FIRCLSCompactUnwindTests.m +++ b/Crashlytics/UnitTests/FIRCLSCompactUnwindTests.m @@ -33,7 +33,7 @@ @implementation FIRCLSCompactUnwindTests - (void)setUp { [super setUp]; - _firclsContext.readonly = malloc(sizeof(FIRCLSReadOnlyContext)); + _firclsContext.readonly = calloc(1, sizeof(FIRCLSReadOnlyContext)); _firclsContext.readonly->logPath = "/tmp/test.log"; } diff --git a/Crashlytics/UnitTests/FIRCLSDwarfTests.m b/Crashlytics/UnitTests/FIRCLSDwarfTests.m index 4dfb98d1c2d..7a97afa1abb 100644 --- a/Crashlytics/UnitTests/FIRCLSDwarfTests.m +++ b/Crashlytics/UnitTests/FIRCLSDwarfTests.m @@ -33,7 +33,7 @@ @implementation FIRCLSDwarfTests - (void)setUp { [super setUp]; - _firclsContext.readonly = malloc(sizeof(FIRCLSReadOnlyContext)); + _firclsContext.readonly = calloc(1, sizeof(FIRCLSReadOnlyContext)); _firclsContext.readonly->logPath = "/tmp/test.log"; } diff --git a/Crashlytics/UnitTests/FIRCLSFileTests.m b/Crashlytics/UnitTests/FIRCLSFileTests.m index b8895f68a67..09e3ba2428c 100644 --- a/Crashlytics/UnitTests/FIRCLSFileTests.m +++ b/Crashlytics/UnitTests/FIRCLSFileTests.m @@ -217,7 +217,7 @@ - (void)hexEncodingLongStringWithFile:(FIRCLSFile *)file filePath:(NSString *)filePath length:(size_t)length buffered:(BOOL)buffered { - char *longString = malloc(length * sizeof(char)); + char *longString = calloc(1, length * sizeof(char)); memset(longString, 'a', length); // fill it with 'a' characters longString[length - 1] = 0; // null terminate @@ -432,7 +432,7 @@ - (void)closeAndOpenAlternatingBufferedOptionWithFile:(FIRCLSFile *)file - (void)testLoggingInputLongerThanBuffer { size_t inputLength = (FIRCLSWriteBufferLength + 2) * sizeof(char); - char *input = malloc(inputLength); + char *input = calloc(1, inputLength); for (size_t i = 0; i < inputLength - 1; i++) { input[i] = i % 26 + 'a'; } diff --git a/Crashlytics/UnitTests/FIRCLSLoggingTests.m b/Crashlytics/UnitTests/FIRCLSLoggingTests.m index b79341fe06e..475d8c79bdb 100644 --- a/Crashlytics/UnitTests/FIRCLSLoggingTests.m +++ b/Crashlytics/UnitTests/FIRCLSLoggingTests.m @@ -302,7 +302,7 @@ - (void)testUserLogNil { - (void)testLargeLogLine { size_t strLength = 100 * 1024; // Attempt to write 100k of data - char* longLine = malloc(strLength + 1); + char* longLine = calloc(1, strLength + 1); memset(longLine, 'a', strLength); longLine[strLength] = '\0'; NSString* longStr = [[NSString alloc] initWithBytesNoCopy:longLine From f53dfc347d52257f4da3727937a9236b9ddde1c4 Mon Sep 17 00:00:00 2001 From: themiswang Date: Mon, 30 Dec 2024 13:10:39 -0500 Subject: [PATCH 96/98] fix comment and migrate to calloc for session (#14295) --- Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c | 16 ++++++++-------- Crashlytics/Crashlytics/Helpers/FIRCLSFile.m | 6 +++--- Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m | 2 +- .../Models/Record/FIRCLSReportAdapter.m | 6 +++--- .../SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h | 4 ++-- .../SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c b/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c index acf78d98496..6c04a7d4f77 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c @@ -56,7 +56,7 @@ FIRCLSAllocatorRef FIRCLSAllocatorCreate(size_t writableSpace, size_t readableSp } // Make one big, continuous allocation, adding additional pages for our guards. Note - // that we cannot use malloc (or valloc) in this case, because we need to assert full + // that we cannot use malloc, calloc (or valloc) in this case, because we need to assert full // ownership over these allocations. mmap is a much better choice. We also mark these // pages as MAP_NOCACHE. allocationSize = writableRegion.size + readableRegion.size + pageSize * 3; @@ -174,10 +174,10 @@ void* FIRCLSAllocatorSafeAllocateFromRegion(FIRCLSAllocationRegion* region, size // this shouldn't happen unless we make a mistake with our size pre-computations if ((uintptr_t)originalCursor - (uintptr_t)region->start + size > region->size) { - FIRCLSSDKLog("Unable to allocate sufficient memory, falling back to malloc\n"); + FIRCLSSDKLog("Unable to allocate sufficient memory, falling back to calloc\n"); void* ptr = calloc(1, size); if (!ptr) { - FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocateFromRegion\n"); + FIRCLSSDKLog("Unable to calloc in FIRCLSAllocatorSafeAllocateFromRegion\n"); return NULL; } return ptr; @@ -195,21 +195,21 @@ void* FIRCLSAllocatorSafeAllocate(FIRCLSAllocatorRef allocator, FIRCLSAllocationRegion* region; if (!allocator) { - // fall back to malloc in this case - FIRCLSSDKLog("Allocator invalid, falling back to malloc\n"); + // fall back to calloc in this case + FIRCLSSDKLog("Allocator invalid, falling back to calloc\n"); void* ptr = calloc(1, size); if (!ptr) { - FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); + FIRCLSSDKLog("Unable to calloc in FIRCLSAllocatorSafeAllocate\n"); return NULL; } return ptr; } if (allocator->protectionEnabled) { - FIRCLSSDKLog("Allocator already protected, falling back to malloc\n"); + FIRCLSSDKLog("Allocator already protected, falling back to calloc\n"); void* ptr = calloc(1, size); if (!ptr) { - FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); + FIRCLSSDKLog("Unable to calloc in FIRCLSAllocatorSafeAllocate\n"); return NULL; } return ptr; diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m b/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m index 1f4d2a0c836..6a2b7fa3a19 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m @@ -76,7 +76,7 @@ static bool FIRCLSFileInit( if (bufferWrites) { file->writeBuffer = calloc(1, FIRCLSWriteBufferLength * sizeof(char)); if (!file->writeBuffer) { - FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileInit"); + FIRCLSErrorLog(@"Unable to calloc in FIRCLSFileInit"); return false; } @@ -671,7 +671,7 @@ void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* val char* encodedBuffer = calloc(1, length * 2 + 1); if (!encodedBuffer) { - FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexEncodeString"); + FIRCLSErrorLog(@"Unable to calloc in FIRCLSFileHexEncodeString"); return nil; } @@ -695,7 +695,7 @@ void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* val size_t length = strlen(string); char* decodedBuffer = calloc(1, length); // too long, but safe if (!decodedBuffer) { - FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexDecodeString"); + FIRCLSErrorLog(@"Unable to calloc in FIRCLSFileHexDecodeString"); return nil; } diff --git a/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m b/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m index 21e87ac66fd..7edb657aeaa 100644 --- a/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m +++ b/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m @@ -188,7 +188,7 @@ void FIRCLSRedactUUID(char* value) { buffer = calloc(1, sizeof(char) * size); if (!buffer) { - FIRCLSErrorLog(@"Unable to malloc in FIRCLSNSDataToNSString"); + FIRCLSErrorLog(@"Unable to calloc in FIRCLSNSDataToNSString"); return nil; } diff --git a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m index 543c6bfc718..6ee57270ef8 100644 --- a/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m +++ b/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m @@ -236,7 +236,7 @@ - (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str { } } -/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. +/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. * @note Memory needs to be freed manually, through pb_free or pb_release. * @param string The string to encode as pb_bytes. */ @@ -251,12 +251,12 @@ - (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str { return FIRCLSEncodeData(stringBytes); } -/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. +/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. * @note Memory needs to be free manually, through pb_free or pb_release. * @param data The data to copy into the new bytes array. */ pb_bytes_array_t *FIRCLSEncodeData(NSData *data) { - // We have received couple security tickets before for using malloc here. + // We have received couple security tickets before for using calloc here. // Here is a short explaination on how it is calculated so buffer overflow is prevented: // We will alloc an amount of memeory for struct `pb_bytes_array_t`, this struct contains two // attributes: diff --git a/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h b/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h index e07f0e344ed..a0d5a6f8c78 100644 --- a/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h +++ b/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h @@ -49,12 +49,12 @@ NSData* _Nullable FIRSESEncodeProto(const pb_field_t fields[], NSError** error); #pragma clang diagnostic pop -/// Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. +/// Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. /// @note Memory needs to be freed manually, through pb_free or pb_release. /// @param data The data to copy into the new bytes array. pb_bytes_array_t* _Nullable FIRSESEncodeData(NSData* _Nullable data); -/// Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. +/// Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. /// @note Memory needs to be freed manually, through pb_free or pb_release. /// @param string The string to encode as pb_bytes. pb_bytes_array_t* _Nullable FIRSESEncodeString(NSString* _Nullable string); diff --git a/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m b/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m index 6440ec4d886..17dd086157a 100644 --- a/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m +++ b/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m @@ -87,12 +87,12 @@ void nanopb_free(void *_Nullable ptr) { } #pragma clang diagnostic pop -/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. +/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. * @note Memory needs to be free manually, through pb_free or pb_release. * @param data The data to copy into the new bytes array. */ pb_bytes_array_t *_Nullable FIRSESEncodeData(NSData *_Nullable data) { - pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + pb_bytes_array_t *pbBytes = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); if (pbBytes == NULL) { return NULL; } @@ -101,7 +101,7 @@ void nanopb_free(void *_Nullable ptr) { return pbBytes; } -/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. +/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. * @note Memory needs to be freed manually, through pb_free or pb_release. * @param string The string to encode as pb_bytes. */ @@ -174,7 +174,7 @@ pb_size_t FIRSESGetAppleApplicationInfoTag(void) { size_t size; sysctlbyname(sysctlKey, NULL, &size, NULL, 0); if (size > 0) { - char *entryValueCStr = malloc(size); + char *entryValueCStr = calloc(1, size); sysctlbyname(sysctlKey, entryValueCStr, &size, NULL, 0); entryValue = [NSString stringWithCString:entryValueCStr encoding:NSUTF8StringEncoding]; free(entryValueCStr); From ffe6cf2fa4951f3293af17b39dce97a025bc68ca Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 3 Jan 2025 10:40:41 -0500 Subject: [PATCH 97/98] Bump Python version from 3.7 to 3.11 in GitHub Actions workflows (#14301) --- .github/workflows/firestore-nightly.yml | 2 +- .github/workflows/firestore.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/firestore-nightly.yml b/.github/workflows/firestore-nightly.yml index dca4a833f19..36beeadb4ac 100644 --- a/.github/workflows/firestore-nightly.yml +++ b/.github/workflows/firestore-nightly.yml @@ -71,7 +71,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: '3.7' + python-version: '3.11' - name: Install Secret GoogleService-Info.plist run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/firestore-nightly.plist.gpg \ diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 065d0b365cc..90c61962c6a 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -15,6 +15,7 @@ name: firestore on: + workflow_dispatch: pull_request: schedule: # Run every day at 12am (PST) - cron uses UTC times @@ -311,7 +312,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: '3.7' + python-version: '3.11' - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ runner.os }} cmake From c092c02dd2840782132e61dfc77558729bf63450 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 6 Jan 2025 12:20:55 -0500 Subject: [PATCH 98/98] [Auth] Refactor MultiFactor.swift (#14241) --- .../Swift/MultiFactor/MultiFactor.swift | 160 +++++++++--------- 1 file changed, 77 insertions(+), 83 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift index 5b1675fdfa0..17ec6b18731 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift @@ -67,6 +67,53 @@ import Foundation displayName: String?, completion: ((Error?) -> Void)?) { // TODO: Refactor classes so this duplicated code isn't necessary for phone and totp. + + guard + assertion.factorID == PhoneMultiFactorInfo.TOTPMultiFactorID || + assertion.factorID == PhoneMultiFactorInfo.PhoneMultiFactorID + else { + return + } + + guard let user, let auth = user.auth else { + fatalError("Internal Auth error: failed to get user enrolling in MultiFactor") + } + + let request = Self.enrollmentFinalizationRequest( + with: assertion, + displayName: displayName, + user: user, + auth: auth + ) + + Task { + do { + let response = try await auth.backend.call(with: request) + let user = try await auth.completeSignIn(withAccessToken: response.idToken, + accessTokenExpirationDate: nil, + refreshToken: response.refreshToken, + anonymous: false) + try auth.updateCurrentUser(user, byForce: false, savingToDisk: true) + if let completion { + DispatchQueue.main.async { + completion(nil) + } + } + } catch { + if let completion { + DispatchQueue.main.async { + completion(error) + } + } + } + } + } + + private static func enrollmentFinalizationRequest(with assertion: MultiFactorAssertion, + displayName: String?, + user: User, + auth: Auth) -> FinalizeMFAEnrollmentRequest { + var request: FinalizeMFAEnrollmentRequest? = nil if assertion.factorID == PhoneMultiFactorInfo.TOTPMultiFactorID { guard let totpAssertion = assertion as? TOTPMultiFactorAssertion else { fatalError("Auth Internal Error: Failed to find TOTPMultiFactorAssertion") @@ -74,97 +121,44 @@ import Foundation switch totpAssertion.secretOrID { case .enrollmentID: fatalError("Missing secret in totpAssertion") case let .secret(secret): - guard let user = user, let auth = user.auth else { - fatalError("Internal Auth error: failed to get user enrolling in MultiFactor") - } let finalizeMFATOTPRequestInfo = AuthProtoFinalizeMFATOTPEnrollmentRequestInfo(sessionInfo: secret.sessionInfo, verificationCode: totpAssertion .oneTimePassword) - let request = FinalizeMFAEnrollmentRequest(idToken: self.user?.rawAccessToken(), - displayName: displayName, - totpVerificationInfo: finalizeMFATOTPRequestInfo, - requestConfiguration: user - .requestConfiguration) - Task { - do { - let response = try await auth.backend.call(with: request) - do { - let user = try await auth.completeSignIn(withAccessToken: response.idToken, - accessTokenExpirationDate: nil, - refreshToken: response.refreshToken, - anonymous: false) - try auth.updateCurrentUser(user, byForce: false, savingToDisk: true) - if let completion { - DispatchQueue.main.async { - completion(nil) - } - } - } catch { - DispatchQueue.main.async { - if let completion { - completion(error) - } - } - } - } catch { - if let completion { - completion(error) - } - } - } + request = FinalizeMFAEnrollmentRequest(idToken: user.rawAccessToken(), + displayName: displayName, + totpVerificationInfo: finalizeMFATOTPRequestInfo, + requestConfiguration: user + .requestConfiguration) } - return - } else if assertion.factorID != PhoneMultiFactorInfo.PhoneMultiFactorID { - return - } - let phoneAssertion = assertion as? PhoneMultiFactorAssertion - guard let credential = phoneAssertion?.authCredential else { - fatalError("Internal Error: Missing credential") - } - switch credential.credentialKind { - case .phoneNumber: fatalError("Internal Error: Missing verificationCode") - case let .verification(verificationID, code): - let finalizeMFAPhoneRequestInfo = - AuthProtoFinalizeMFAPhoneRequestInfo(sessionInfo: verificationID, verificationCode: code) - guard let user = user, let auth = user.auth else { - fatalError("Internal Auth error: failed to get user enrolling in MultiFactor") + } else if assertion.factorID == PhoneMultiFactorInfo.PhoneMultiFactorID { + let phoneAssertion = assertion as? PhoneMultiFactorAssertion + guard let credential = phoneAssertion?.authCredential else { + fatalError("Internal Error: Missing credential") } - let request = FinalizeMFAEnrollmentRequest( - idToken: self.user?.rawAccessToken(), - displayName: displayName, - phoneVerificationInfo: finalizeMFAPhoneRequestInfo, - requestConfiguration: user.requestConfiguration - ) - - Task { - do { - let response = try await auth.backend.call(with: request) - do { - let user = try await auth.completeSignIn(withAccessToken: response.idToken, - accessTokenExpirationDate: nil, - refreshToken: response.refreshToken, - anonymous: false) - try auth.updateCurrentUser(user, byForce: false, savingToDisk: true) - if let completion { - DispatchQueue.main.async { - completion(nil) - } - } - } catch { - DispatchQueue.main.async { - if let completion { - completion(error) - } - } - } - } catch { - if let completion { - completion(error) - } - } + switch credential.credentialKind { + case .phoneNumber: fatalError("Internal Error: Missing verificationCode") + case let .verification(verificationID, code): + let finalizeMFAPhoneRequestInfo = + AuthProtoFinalizeMFAPhoneRequestInfo( + sessionInfo: verificationID, + verificationCode: code + ) + request = FinalizeMFAEnrollmentRequest( + idToken: user.rawAccessToken(), + displayName: displayName, + phoneVerificationInfo: finalizeMFAPhoneRequestInfo, + requestConfiguration: user.requestConfiguration + ) } } + + guard let request else { + // Assertion is not a phone assertion or TOTP assertion. + fatalError("Internal Error: Unsupported assertion with factor ID: \(assertion.factorID).") + } + + return request } /// Enrolls a second factor as identified by the `MultiFactorAssertion` parameter for the

wFr$+#U{60owelNc(Z^kwlEBme#5<+9*5)_mq2 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 -> some View { + HStack { + Image(systemName: symbolName) + .foregroundColor(.orange) + .imageScale(.large) + .padding(.leading) + configuration + .padding([.vertical, .trailing]) + } + .background(Color(uiColor: .secondarySystemBackground)) + .cornerRadius(14) + .textInputAutocapitalization(.never) } +} - private func setupCreateAccountButton() { - addSubview(createAccountButton) - createAccountButton.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - createAccountButton.centerXAnchor.constraint(equalTo: centerXAnchor), - createAccountButton.topAnchor.constraint(equalTo: loginButton.bottomAnchor, constant: 5), - ]) +private struct CustomButtonStyle: ButtonStyle { + let backgroundColor: Color + let foregroundColor: Color + func makeBody(configuration: Configuration) -> some View { + HStack { + Spacer() + configuration.label + Spacer() + } + .padding() + .background(backgroundColor, in: RoundedRectangle(cornerRadius: 14)) + .foregroundStyle(foregroundColor) + .opacity(configuration.isPressed ? 0.5 : 1) } +} - // MARK: - Private Helpers - - private func textField(placeholder: String, symbolName: String) -> UITextField { - let textfield = UITextField() - textfield.backgroundColor = .secondarySystemBackground - textfield.layer.cornerRadius = 14 - textfield.placeholder = placeholder - textfield.tintColor = .systemOrange - let symbol = UIImage(systemName: symbolName) - textfield.setImage(symbol) - return textfield - } +#Preview { + LoginView() } diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/Extensions.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/Extensions.swift index a004534ad7d..33aab86f922 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/Extensions.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/Utility/Extensions.swift @@ -13,6 +13,7 @@ // limitations under the License. import FirebaseAuth +import SwiftUI import UIKit // MARK: - Extending a `Firebase User` to conform to `DataSourceProvidable` diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift index 7f8b77856f0..9ed87073372 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/AuthViewController.swift @@ -16,6 +16,8 @@ // [START auth_import] import FirebaseCore +import SwiftUI + // For Sign in with Facebook import FBSDKLoginKit @@ -180,7 +182,7 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { phoneEnroll() case .totpEnroll: - totpEnroll() + Task { await totpEnroll() } case .multifactorUnenroll: mfaUnenroll() @@ -336,9 +338,10 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { } private func performDemoEmailPasswordLoginFlow() { - let loginController = LoginController() - loginController.delegate = self - navigationController?.pushViewController(loginController, animated: true) + let loginView = LoginView(delegate: self) + let hostingController = UIHostingController(rootView: loginView) + hostingController.title = "Email/Password Auth" + navigationController?.pushViewController(hostingController, animated: true) } private func performPasswordlessLoginFlow() { @@ -786,89 +789,53 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { } } - private func totpEnroll() { - guard let user = AppManager.shared.auth().currentUser else { - print("Error: User must be logged in first.") + private func totpEnroll() async { + guard + let user = AppManager.shared.auth().currentUser, + let accountName = user.email + else { + showAlert(for: "Enrollment failed: User must be logged and have email address.") return } - user.multiFactor.getSessionWithCompletion { session, error in - guard let session = session, error == nil else { - if let error = error { - self.showAlert(for: "Enrollment failed") - print("Multi factor start enroll failed. Error: \(error.localizedDescription)") - } else { - self.showAlert(for: "Enrollment failed") - print("Multi factor start enroll failed with unknown error.") - } + guard let issuer = AppManager.shared.auth().app?.name else { + showAlert(for: "Enrollment failed: Firebase app is missing name.") + return + } + + do { + let session = try await user.multiFactor.session() + let secret = try await TOTPMultiFactorGenerator.generateSecret(with: session) + print("Secret: " + secret.sharedSecretKey()) + + let url = secret.generateQRCodeURL(withAccountName: accountName, issuer: issuer) + guard !url.isEmpty else { + showAlert(for: "Enrollment failed") + print("Multi factor finalize enroll failed. Could not generate URL.") return } + secret.openInOTPApp(withQRCodeURL: url) - TOTPMultiFactorGenerator.generateSecret(with: session) { secret, error in - guard let secret = secret, error == nil else { - if let error = error { - self.showAlert(for: "Enrollment failed") - print("Error generating TOTP secret. Error: \(error.localizedDescription)") - } else { - self.showAlert(for: "Enrollment failed") - print("Error generating TOTP secret.") - } - return - } - - guard let accountName = user.email, let issuer = Auth.auth().app?.name else { - self.showAlert(for: "Enrollment failed") - print("Multi factor finalize enroll failed. Could not get account details.") - return - } - - DispatchQueue.main.async { - let url = secret.generateQRCodeURL(withAccountName: accountName, issuer: issuer) - - guard !url.isEmpty else { - self.showAlert(for: "Enrollment failed") - print("Multi factor finalize enroll failed. Could not generate URL.") - return - } - - secret.openInOTPApp(withQRCodeURL: url) - - self - .showQRCodePromptWithTextInput(with: "Scan this QR code and enter OTP:", - url: url) { oneTimePassword in - guard !oneTimePassword.isEmpty else { - self.showAlert(for: "Display name must not be empty") - print("OTP not entered.") - return - } + guard + let oneTimePassword = await showTextInputPrompt(with: "Enter the one time passcode.") + else { + showAlert(for: "Enrollment failed: one time passcode not entered.") + return + } - let assertion = TOTPMultiFactorGenerator.assertionForEnrollment( - with: secret, - oneTimePassword: oneTimePassword - ) + let assertion = TOTPMultiFactorGenerator.assertionForEnrollment( + with: secret, + oneTimePassword: oneTimePassword + ) - self.showTextInputPrompt(with: "Display Name") { displayName in - guard !displayName.isEmpty else { - self.showAlert(for: "Display name must not be empty") - print("Display name not entered.") - return - } + // TODO(nickcooke): Provide option to enter display name. + try await user.multiFactor.enroll(with: assertion, displayName: "TOTP") - user.multiFactor.enroll(with: assertion, displayName: displayName) { error in - if let error = error { - self.showAlert(for: "Enrollment failed") - print( - "Multi factor finalize enroll failed. Error: \(error.localizedDescription)" - ) - } else { - self.showAlert(for: "Successfully enrolled: \(displayName)") - print("Multi factor finalize enroll succeeded.") - } - } - } - } - } - } + showAlert(for: "Successfully enrolled: TOTP") + print("Multi factor finalize enroll succeeded.") + } catch { + print(error) + showAlert(for: "Enrollment failed: \(error.localizedDescription)") } } @@ -964,60 +931,12 @@ class AuthViewController: UIViewController, DataSourceProviderDelegate { present(editController, animated: true, completion: nil) } - private func showQRCodePromptWithTextInput(with message: String, url: String, - completion: ((String) -> Void)? = nil) { - // Create a UIAlertController - let alertController = UIAlertController( - title: "QR Code Prompt", - message: message, - preferredStyle: .alert - ) - - // Add a text field for input - alertController.addTextField { textField in - textField.placeholder = "Enter text" - } - - // Create a UIImage from the URL - guard let image = generateQRCode(from: url) else { - print("Failed to generate QR code") - return - } - - // Create an image view to display the QR code - let imageView = UIImageView(image: image) - imageView.contentMode = .scaleAspectFit - imageView.translatesAutoresizingMaskIntoConstraints = false - - // Add the image view to the alert controller - alertController.view.addSubview(imageView) - - // Add constraints to position the image view - NSLayoutConstraint.activate([ - imageView.topAnchor.constraint(equalTo: alertController.view.topAnchor, constant: 20), - imageView.centerXAnchor.constraint(equalTo: alertController.view.centerXAnchor), - imageView.widthAnchor.constraint(equalToConstant: 200), - imageView.heightAnchor.constraint(equalToConstant: 200), - ]) - - // Add actions - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) - let submitAction = UIAlertAction(title: "Submit", style: .default) { _ in - if let completion, - let text = alertController.textFields?.first?.text { - completion(text) + private func showTextInputPrompt(with message: String) async -> String? { + await withCheckedContinuation { continuation in + showTextInputPrompt(with: message) { inputText in + continuation.resume(returning: inputText.isEmpty ? nil : inputText) } } - - alertController.addAction(cancelAction) - alertController.addAction(submitAction) - - // Present the alert controller - UIApplication.shared.windows.first?.rootViewController?.present( - alertController, - animated: true, - completion: nil - ) } // Function to generate QR code from a string diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift deleted file mode 100644 index 36befea2bfd..00000000000 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/ViewControllers/LoginController.swift +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2020 Google LLC -// -// 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 FirebaseAuth -import UIKit - -class LoginController: UIViewController { - weak var delegate: (any LoginDelegate)? - - private var loginView: LoginView { view as! LoginView } - - private var email: String { loginView.emailTextField.text! } - private var password: String { loginView.passwordTextField.text! } - - // Hides tab bar when view controller is presented - override var hidesBottomBarWhenPushed: Bool { get { true } set {} } - - // MARK: - View Controller Lifecycle Methods - - override func loadView() { - view = LoginView() - } - - override func viewDidLoad() { - super.viewDidLoad() - configureNavigationBar() - configureDelegatesAndHandlers() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.setTitleColor(.label) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - view.endEditing(true) - navigationController?.setTitleColor(.systemOrange) - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - navigationController?.popViewController(animated: false) - } - - // Dismisses keyboard when view is tapped - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - super.touchesBegan(touches, with: event) - view.endEditing(true) - } - - // MARK: - Firebase 🔥 - - private func login(with email: String, password: String) { - AppManager.shared.auth().signIn(withEmail: email, password: password) { result, error in - if let error { - let authError = error as NSError - if authError.code == AuthErrorCode.secondFactorRequired.rawValue { - let resolver = authError - .userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver - self.delegate?.loginDidOccur(resolver: resolver) - } else { - self.displayError(error) - } - } else { - self.delegate?.loginDidOccur(resolver: nil) - } - } - } - - private func createUser(email: String, password: String) { - AppManager.shared.auth().createUser(withEmail: email, password: password) { authResult, error in - guard error == nil else { return self.displayError(error) } - self.delegate?.loginDidOccur(resolver: nil) - } - } - - // MARK: - Action Handlers - - @objc - private func handleLogin() { - login(with: email, password: password) - } - - @objc - private func handleCreateAccount() { - createUser(email: email, password: password) - } - - // MARK: - UI Configuration - - private func configureNavigationBar() { - navigationItem.title = "Welcome" - navigationItem.backBarButtonItem?.tintColor = .systemYellow - navigationController?.navigationBar.prefersLargeTitles = true - } - - private func configureDelegatesAndHandlers() { - loginView.emailTextField.delegate = self - loginView.passwordTextField.delegate = self - loginView.loginButton.addTarget(self, action: #selector(handleLogin), for: .touchUpInside) - loginView.createAccountButton.addTarget( - self, - action: #selector(handleCreateAccount), - for: .touchUpInside - ) - } - - override func viewWillTransition(to size: CGSize, - with coordinator: any UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - loginView.emailTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 15 : 50 - loginView.passwordTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 5 : 20 - } -} - -// MARK: - UITextFieldDelegate - -extension LoginController: UITextFieldDelegate { - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - if loginView.emailTextField.isFirstResponder, loginView.passwordTextField.text!.isEmpty { - loginView.passwordTextField.becomeFirstResponder() - } else { - textField.resignFirstResponder() - } - return true - } -} From 3a470b021c0052a258ee8db396994c2e2aad713d Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:03:58 -0500 Subject: [PATCH 84/98] [NFC] Update FirebaseRemoteConfigInterop.podspec (#14253) --- FirebaseRemoteConfigInterop.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 6c18a8d3f05..40c38f2ff31 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -5,7 +5,7 @@ Pod::Spec.new do |s| s.description = <<-DESC Not for public use. - A set of protocols that other Firebase SDKs can use to interoperate with FirebaseRemoetConfig in a safe + A set of protocols that other Firebase SDKs can use to interoperate with FirebaseRemoteConfig in a safe and reliable manner. DESC From 0d569cf84b2022a34b2980e6174e0c2c57af98e3 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:11:40 -0500 Subject: [PATCH 85/98] Fix: sort document reference by long type id (#14248) --- .../Tests/Integration/API/FIRQueryTests.mm | 92 +++++++++++++++++++ Firestore/core/src/model/base_path.h | 44 ++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm index 9afd1b469f1..b1cd36a5c49 100644 --- a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm +++ b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm @@ -804,6 +804,98 @@ - (void)testCollectionGroupQueriesWithStartAtEndAtWithArbitraryDocumentIDs { XCTAssertEqualObjects(ids, (@[ @"cg-doc2" ])); } +- (void)testSnapshotListenerSortsQueryByDocumentIdInTheSameOrderAsServer { + FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{ + @"A" : @{@"a" : @1}, + @"a" : @{@"a" : @1}, + @"Aa" : @{@"a" : @1}, + @"7" : @{@"a" : @1}, + @"12" : @{@"a" : @1}, + @"__id7__" : @{@"a" : @1}, + @"__id12__" : @{@"a" : @1}, + @"__id-2__" : @{@"a" : @1}, + @"__id1_" : @{@"a" : @1}, + @"_id1__" : @{@"a" : @1}, + @"__id" : @{@"a" : @1}, + @"__id9223372036854775807__" : @{@"a" : @1}, + @"__id-9223372036854775808__" : @{@"a" : @1}, + }]; + + FIRQuery *query = [collRef queryOrderedByFieldPath:[FIRFieldPath documentID]]; + NSArray *expectedDocs = @[ + @"__id-9223372036854775808__", @"__id-2__", @"__id7__", @"__id12__", + @"__id9223372036854775807__", @"12", @"7", @"A", @"Aa", @"__id", @"__id1_", @"_id1__", @"a" + ]; + FIRQuerySnapshot *getSnapshot = [self readDocumentSetForRef:query]; + XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(getSnapshot), expectedDocs); + + id registration = + [query addSnapshotListener:self.eventAccumulator.valueEventHandler]; + FIRQuerySnapshot *watchSnapshot = [self.eventAccumulator awaitEventWithName:@"Snapshot"]; + XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(watchSnapshot), expectedDocs); + + [registration remove]; +} + +- (void)testSnapshotListenerSortsFilteredQueryByDocumentIdInTheSameOrderAsServer { + FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{ + @"A" : @{@"a" : @1}, + @"a" : @{@"a" : @1}, + @"Aa" : @{@"a" : @1}, + @"7" : @{@"a" : @1}, + @"12" : @{@"a" : @1}, + @"__id7__" : @{@"a" : @1}, + @"__id12__" : @{@"a" : @1}, + @"__id-2__" : @{@"a" : @1}, + @"__id1_" : @{@"a" : @1}, + @"_id1__" : @{@"a" : @1}, + @"__id" : @{@"a" : @1}, + @"__id9223372036854775807__" : @{@"a" : @1}, + @"__id-9223372036854775808__" : @{@"a" : @1}, + }]; + + FIRQuery *query = [[[collRef queryWhereFieldPath:[FIRFieldPath documentID] + isGreaterThan:@"__id7__"] + queryWhereFieldPath:[FIRFieldPath documentID] + isLessThanOrEqualTo:@"A"] queryOrderedByFieldPath:[FIRFieldPath documentID]]; + NSArray *expectedDocs = + @[ @"__id12__", @"__id9223372036854775807__", @"12", @"7", @"A" ]; + FIRQuerySnapshot *getSnapshot = [self readDocumentSetForRef:query]; + XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(getSnapshot), expectedDocs); + + id registration = + [query addSnapshotListener:self.eventAccumulator.valueEventHandler]; + FIRQuerySnapshot *watchSnapshot = [self.eventAccumulator awaitEventWithName:@"Snapshot"]; + XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(watchSnapshot), expectedDocs); + + [registration remove]; +} + +- (void)testSdkOrdersQueryByDocumentIdTheSameWayOnlineAndOffline { + FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{ + @"A" : @{@"a" : @1}, + @"a" : @{@"a" : @1}, + @"Aa" : @{@"a" : @1}, + @"7" : @{@"a" : @1}, + @"12" : @{@"a" : @1}, + @"__id7__" : @{@"a" : @1}, + @"__id12__" : @{@"a" : @1}, + @"__id-2__" : @{@"a" : @1}, + @"__id1_" : @{@"a" : @1}, + @"_id1__" : @{@"a" : @1}, + @"__id" : @{@"a" : @1}, + @"__id9223372036854775807__" : @{@"a" : @1}, + @"__id-9223372036854775808__" : @{@"a" : @1}, + }]; + + [self checkOnlineAndOfflineQuery:[collRef queryOrderedByFieldPath:[FIRFieldPath documentID]] + matchesResult:@[ + @"__id-9223372036854775808__", @"__id-2__", @"__id7__", @"__id12__", + @"__id9223372036854775807__", @"12", @"7", @"A", @"Aa", @"__id", @"__id1_", + @"_id1__", @"a" + ]]; +} + - (void)testCollectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIDs { // Use .document() to get a random collection group name to use but ensure it starts with 'b' // for predictable ordering. diff --git a/Firestore/core/src/model/base_path.h b/Firestore/core/src/model/base_path.h index 3d604f6bf4e..e8efa395e8d 100644 --- a/Firestore/core/src/model/base_path.h +++ b/Firestore/core/src/model/base_path.h @@ -150,8 +150,18 @@ class BasePath { std::equal(begin(), end(), potential_child.begin()); } + /** + * Compares the current path against another Path object. Paths are compared + * segment by segment, prioritizing numeric IDs (e.g., "__id123__") in numeric + * ascending order, followed by string segments in lexicographical order. + */ util::ComparisonResult CompareTo(const T& rhs) const { - return util::CompareContainer(segments_, rhs.segments_); + size_t min_size = std::min(size(), rhs.size()); + for (size_t i = 0; i < min_size; ++i) { + auto cmp = CompareSegments(segments_[i], rhs.segments_[i]); + if (!util::Same(cmp)) return cmp; + } + return util::Compare(size(), rhs.size()); } friend bool operator==(const BasePath& lhs, const BasePath& rhs) { @@ -174,6 +184,38 @@ class BasePath { private: SegmentsT segments_; + + static const size_t kNumericIdPrefixLength = 4; + static const size_t kNumericIdSuffixLength = 2; + static const size_t kNumericIdTotalOverhead = + kNumericIdPrefixLength + kNumericIdSuffixLength; + + static util::ComparisonResult CompareSegments(const std::string& lhs, + const std::string& rhs) { + bool isLhsNumeric = IsNumericId(lhs); + bool isRhsNumeric = IsNumericId(rhs); + + if (isLhsNumeric && !isRhsNumeric) { + return util::ComparisonResult::Ascending; + } else if (!isLhsNumeric && isRhsNumeric) { + return util::ComparisonResult::Descending; + } else if (isLhsNumeric && isRhsNumeric) { + return util::Compare(ExtractNumericId(lhs), ExtractNumericId(rhs)); + } else { + return util::Compare(lhs, rhs); + } + } + + static bool IsNumericId(const std::string& segment) { + return segment.size() > kNumericIdTotalOverhead && + segment.substr(0, kNumericIdPrefixLength) == "__id" && + segment.substr(segment.size() - kNumericIdSuffixLength) == "__"; + } + + static int64_t ExtractNumericId(const std::string& segment) { + return std::stol(segment.substr(kNumericIdPrefixLength, + segment.size() - kNumericIdSuffixLength)); + } }; } // namespace impl From 3591c679c47049aac106eeef149af68c04d9f9fc Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Wed, 18 Dec 2024 18:36:18 +0330 Subject: [PATCH 86/98] [FirebaseVertexAI] test: fix assertion `message` spelling (#14268) --- FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift index cf5e6a1eadf..879013c917e 100644 --- a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift +++ b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift @@ -116,7 +116,7 @@ final class PartsRepresentableTests: XCTestCase { "Got unexpected error type: \(errorPart.error)" ) guard case .invalidUnderlyingImage = imageError else { - XCTFail("Expected invalid underyling image conversion error, got \(imageError) instead.") + XCTFail("Expected invalid underlying image conversion error, got \(imageError) instead.") return } } From 1fa25d0dec28c1eaee6afd2fb0c3750643d1ff1c Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Wed, 18 Dec 2024 18:48:35 +0330 Subject: [PATCH 87/98] [FirebaseMessaging] fix: typo in the word `formatted` (#14271) --- FirebaseMessaging/Apps/Shared/LiveActivityView.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/FirebaseMessaging/Apps/Shared/LiveActivityView.swift b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift index e91bd4fd08f..112787271fa 100644 --- a/FirebaseMessaging/Apps/Shared/LiveActivityView.swift +++ b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift @@ -66,14 +66,14 @@ struct LiveActivityView: View { let ptsToken = Activity.pushToStartToken if ptsToken != nil { - let ptsTokenString = getFormatedToken(token: ptsToken!) + let ptsTokenString = getFormattedToken(token: ptsToken!) activityTokenDict["PTS"] = ptsTokenString } else { activityTokenDict["PTS"] = "Not available yet.!" Task { for await ptsToken in Activity .pushToStartTokenUpdates { - let ptsTokenString = getFormatedToken(token: ptsToken) + let ptsTokenString = getFormattedToken(token: ptsToken) activityTokenDict["PTS"] = ptsTokenString refreshAcitivtyList() } @@ -83,7 +83,7 @@ struct LiveActivityView: View { let activities = Activity.activities for activity in activities { if activity.pushToken != nil { - let activityToken = getFormatedToken(token: activity.pushToken!) + let activityToken = getFormattedToken(token: activity.pushToken!) activityTokenDict[activity.id] = activityToken } else { activityTokenDict[activity.id] = "Not available yet!" @@ -92,7 +92,7 @@ struct LiveActivityView: View { } } - func getFormatedToken(token: Data) -> String { + func getFormattedToken(token: Data) -> String { return token.reduce("") { $0 + String(format: "%02x", $1) } @@ -114,7 +114,7 @@ struct LiveActivityView: View { if activity != nil { Task { for await pushToken in activity!.pushTokenUpdates { - let activityToken = getFormatedToken(token: pushToken) + let activityToken = getFormattedToken(token: pushToken) activityTokenDict[activity!.id] = activityToken refreshAcitivtyList() } From 46f2a90f9e18e34c6994a4794f451d82f42e2365 Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Wed, 18 Dec 2024 18:48:45 +0330 Subject: [PATCH 88/98] [FirebaseAuth] docs: enhance code documentations (#14269) --- FirebaseAuth/Sources/Swift/User/User.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index fccd96ab088..db128df0baa 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -1764,7 +1764,7 @@ extension User: NSSecureCoding {} requestConfiguration = AuthRequestConfiguration(apiKey: apiKey ?? "", appID: appID ?? "") // This property will be overwritten later via the `user.auth` property update. For now, a - // placeholder is set as the property update should happen right after this intializer. + // placeholder is set as the property update should happen right after this initializer. backend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer()) userProfileUpdate = UserProfileUpdate() From badde0a466b6112ded6ab0bd36a988b7b0ee0da8 Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Wed, 18 Dec 2024 18:51:50 +0330 Subject: [PATCH 89/98] [FirebaseMessaging] docs: enhance the readme text (#14270) --- FirebaseMessaging/Apps/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseMessaging/Apps/README.md b/FirebaseMessaging/Apps/README.md index f80410f3200..0afad7e905a 100644 --- a/FirebaseMessaging/Apps/README.md +++ b/FirebaseMessaging/Apps/README.md @@ -7,7 +7,7 @@ the sample code. The one inside the AdvancedSample folder is a test app based on the test app in the Sample folder. Both Apps share most of the code in the main target. The AdvancedSample app provides advanced app extensions features, such as Notification Service Extension, Shared -Extension, App Clips, Live Activites and a watchOS app. The advanced sample app has more +Extension, App Clips, Live Activities and a watchOS app. The advanced sample app has more targets than the Sample app and requires your own provisioning profiles and certificates for each extension target to be setup so that it can be run on a real device. From dd8b502034b558d4f642c792a1ea215f2edfffbb Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:09:39 -0500 Subject: [PATCH 90/98] [Storage] Add preconcurrency attribute to class (#14272) --- FirebaseStorage/Sources/Internal/StorageInternalTask.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseStorage/Sources/Internal/StorageInternalTask.swift b/FirebaseStorage/Sources/Internal/StorageInternalTask.swift index bf2e858cd6e..aac100bb5e1 100644 --- a/FirebaseStorage/Sources/Internal/StorageInternalTask.swift +++ b/FirebaseStorage/Sources/Internal/StorageInternalTask.swift @@ -22,6 +22,7 @@ import Foundation /// Implement StorageTasks that are not directly exposed via the public API. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +@preconcurrency class StorageInternalTask: StorageTask { private var fetcher: GTMSessionFetcher? From afd83c304db49c0da5818f87d7f661c02ab9e3d9 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 20 Dec 2024 15:14:19 -0800 Subject: [PATCH 91/98] [auth] Address Xcode 16.2 concurrency compile time issues (#14279) --- FirebaseAuth/CHANGELOG.md | 1 + FirebaseAuth/Sources/Swift/Auth/Auth.swift | 1 + .../Sources/Swift/SystemService/AuthNotificationManager.swift | 1 + 3 files changed, 3 insertions(+) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 8940131c5c3..42f0ff36650 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -2,6 +2,7 @@ - [fixed] Fix Multi-factor session crash on second Firebase app. (#14238) - [fixed] Updated most decoders to be consistent with Firebase 10's behavior for decoding `nil` values. (#14212) +- [fixed] Address Xcode 16.2 concurrency compile time issues. (#14279) # 11.6.0 - [added] Added reCAPTCHA Enterprise support for app verification during phone diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index 27aeccf4ece..814588201a1 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -144,6 +144,7 @@ extension Auth: AuthInterop { /// /// This class is thread-safe. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +@preconcurrency @objc(FIRAuth) open class Auth: NSObject { /// Gets the auth object for the default Firebase app. /// diff --git a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift index 1dbb6c9c435..94b0960f53a 100644 --- a/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift +++ b/FirebaseAuth/Sources/Swift/SystemService/AuthNotificationManager.swift @@ -18,6 +18,7 @@ /// A class represents a credential that proves the identity of the app. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) + @preconcurrency class AuthNotificationManager { /// The key to locate payload data in the remote notification. private let kNotificationDataKey = "com.google.firebase.auth" From cf3e90246036a13a3ed3a7c257f130642a3f49c3 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 20 Dec 2024 17:25:54 -0800 Subject: [PATCH 92/98] [auth] Fix handling of cloud blocking function errors (#14280) --- FirebaseAuth/CHANGELOG.md | 1 + .../Sources/Swift/Backend/AuthBackend.swift | 16 +++-- .../Swift/Utilities/AuthErrorUtils.swift | 65 +++++++++++++++---- .../Sources/Swift/Utilities/AuthErrors.swift | 2 +- .../Tests/Unit/AuthBackendTests.swift | 45 +++++++++++++ 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 42f0ff36650..bce9975d100 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -3,6 +3,7 @@ - [fixed] Updated most decoders to be consistent with Firebase 10's behavior for decoding `nil` values. (#14212) - [fixed] Address Xcode 16.2 concurrency compile time issues. (#14279) +- [fixed] Fix handling of cloud blocking function errors. (#14052) # 11.6.0 - [added] Added reCAPTCHA Enterprise support for app verification during phone diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 61be56b09ca..2915b8d7044 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -293,14 +293,22 @@ final class AuthBackend: AuthBackendProtocol { .unexpectedErrorResponse(deserializedResponse: dictionary, underlyingError: error) } + private static func splitStringAtFirstColon(_ input: String) -> (before: String, after: String) { + guard let colonIndex = input.firstIndex(of: ":") else { + return (input, "") // No colon, return original string before and empty after + } + let before = String(input.prefix(upTo: colonIndex)) + .trimmingCharacters(in: .whitespacesAndNewlines) + let after = String(input.suffix(from: input.index(after: colonIndex))) + .trimmingCharacters(in: .whitespacesAndNewlines) + return (before, after.isEmpty ? "" : after) // Return empty after if it's empty + } + private static func clientError(withServerErrorMessage serverErrorMessage: String, errorDictionary: [String: Any], response: AuthRPCResponse?, error: Error?) -> Error? { - let split = serverErrorMessage.split(separator: ":") - let shortErrorMessage = split.first?.trimmingCharacters(in: .whitespacesAndNewlines) - let serverDetailErrorMessage = String(split.count > 1 ? split[1] : "") - .trimmingCharacters(in: .whitespacesAndNewlines) + let (shortErrorMessage, serverDetailErrorMessage) = splitStringAtFirstColon(serverErrorMessage) switch shortErrorMessage { case "USER_NOT_FOUND": return AuthErrorUtils .userNotFoundError(message: serverDetailErrorMessage) diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift index ee397bfc670..ff0f9696130 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift @@ -510,25 +510,62 @@ class AuthErrorUtils { return error(code: .accountExistsWithDifferentCredential, userInfo: userInfo) } + private static func extractJSONObjectFromString(from string: String) -> [String: Any]? { + // 1. Find the start of the JSON object. + guard let start = string.firstIndex(of: "{") else { + return nil // No JSON object found + } + // 2. Find the end of the JSON object. + // Start from the first curly brace `{` + var curlyLevel = 0 + var endIndex: String.Index? + + for index in string.indices.suffix(from: start) { + let char = string[index] + if char == "{" { + curlyLevel += 1 + } else if char == "}" { + curlyLevel -= 1 + if curlyLevel == 0 { + endIndex = index + break + } + } + } + guard let end = endIndex else { + return nil // Unbalanced curly braces + } + + // 3. Extract the JSON string. + let jsonString = String(string[start ... end]) + + // 4. Convert JSON String to JSON Object + guard let jsonData = jsonString.data(using: .utf8) else { + return nil // Could not convert String to Data + } + + do { + if let jsonObject = try JSONSerialization + .jsonObject(with: jsonData, options: []) as? [String: Any] { + return jsonObject + } else { + return nil // JSON Object is not a dictionary + } + } catch { + return nil // Failed to deserialize JSON + } + } + static func blockingCloudFunctionServerResponse(message: String?) -> Error { guard let message else { return error(code: .blockingCloudFunctionError, message: message) } - var jsonString = message.replacingOccurrences( - of: "HTTP Cloud Function returned an error:", - with: "" - ) - jsonString = jsonString.trimmingCharacters(in: .whitespaces) - let jsonData = jsonString.data(using: .utf8) ?? Data() - do { - let jsonDict = try JSONSerialization - .jsonObject(with: jsonData, options: []) as? [String: Any] ?? [:] - let errorDict = jsonDict["error"] as? [String: Any] ?? [:] - let errorMessage = errorDict["message"] as? String - return error(code: .blockingCloudFunctionError, message: errorMessage) - } catch { - return JSONSerializationError(underlyingError: error) + guard let jsonDict = extractJSONObjectFromString(from: message) else { + return error(code: .blockingCloudFunctionError, message: message) } + let errorDict = jsonDict["error"] as? [String: Any] ?? [:] + let errorMessage = errorDict["message"] as? String + return error(code: .blockingCloudFunctionError, message: errorMessage) } #if os(iOS) diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift index 7f73876e89c..d4a8a2595f8 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrors.swift @@ -303,7 +303,7 @@ import Foundation /// Indicates that the nonce is missing or invalid. case missingOrInvalidNonce = 17094 - /// Raised when n Cloud Function returns a blocking error. Will include a message returned from + /// Raised when a Cloud Function returns a blocking error. Will include a message returned from /// the function. case blockingCloudFunctionError = 17105 diff --git a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift index 748a5ba1982..73a74691e78 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendTests.swift @@ -372,6 +372,51 @@ class AuthBackendTests: RPCBaseTests { } } + /// Test Blocking Function Error Response flow + func testBlockingFunctionError() async throws { + let kErrorMessageBlocking = "BLOCKING_FUNCTION_ERROR_RESPONSE" + let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode) + let request = FakeRequest(withRequestBody: [:]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond(serverErrorMessage: kErrorMessageBlocking, error: responseError) + } + do { + let _ = try await authBackend.call(with: request) + XCTFail("Expected to throw") + } catch { + let rpcError = error as NSError + XCTAssertEqual(rpcError.domain, AuthErrors.domain) + XCTAssertEqual(rpcError.code, AuthErrorCode.blockingCloudFunctionError.rawValue) + } + } + + /// Test Blocking Function Error Response flow - including JSON parsing. + /// Regression Test for #14052 + func testBlockingFunctionErrorWithJSON() async throws { + let kErrorMessageBlocking = "BLOCKING_FUNCTION_ERROR_RESPONSE" + let stringWithJSON = "BLOCKING_FUNCTION_ERROR_RESPONSE : ((HTTP request to" + + "http://127.0.0.1:9999/project-id/us-central1/beforeUserCreated returned HTTP error 400:" + + " {\"error\":{\"details\":{\"code\":\"invalid-email\"},\"message\":\"invalid " + + "email\",\"status\":\"INVALID_ARGUMENT\"}}))" + let responseError = NSError(domain: kFakeErrorDomain, code: kFakeErrorCode) + let request = FakeRequest(withRequestBody: [:]) + rpcIssuer.respondBlock = { + try self.rpcIssuer.respond( + serverErrorMessage: kErrorMessageBlocking + " : " + stringWithJSON, + error: responseError + ) + } + do { + let _ = try await authBackend.call(with: request) + XCTFail("Expected to throw") + } catch { + let rpcError = error as NSError + XCTAssertEqual(rpcError.domain, AuthErrors.domain) + XCTAssertEqual(rpcError.code, AuthErrorCode.blockingCloudFunctionError.rawValue) + XCTAssertEqual(rpcError.localizedDescription, "invalid email") + } + } + /** @fn testDecodableErrorResponseWithUnknownMessage @brief This test checks the behaviour of @c postWithRequest:response:callback: when the response deserialized by @c NSJSONSerialization represents a valid error response (and an From 5006c2ae28ebb625f525792a10272d7f27c2c7c7 Mon Sep 17 00:00:00 2001 From: themiswang Date: Mon, 23 Dec 2024 11:30:07 -0500 Subject: [PATCH 93/98] bump upload-symbols to 3.20 (#14261) --- Crashlytics/CHANGELOG.md | 3 +++ Crashlytics/CrashlyticsInputFiles.xcfilelist | 1 + Crashlytics/upload-symbols | Bin 810048 -> 809952 bytes 3 files changed, 4 insertions(+) diff --git a/Crashlytics/CHANGELOG.md b/Crashlytics/CHANGELOG.md index 0f239714aab..59058cf574c 100644 --- a/Crashlytics/CHANGELOG.md +++ b/Crashlytics/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Updated `upload-symbols` to version 3.20, wait for `debug.dylib` DWARF content getting generated when build with `--build-phase` option. Added `debug.dylib` DWARF content to run script input file list for user who enabled user script sandboxing (#14054). + # 11.5.0 - [changed] Updated `upload-symbols` to version 3.19, removed all methods require CFRelease and switch to modern classes (#13420). diff --git a/Crashlytics/CrashlyticsInputFiles.xcfilelist b/Crashlytics/CrashlyticsInputFiles.xcfilelist index d4926e82da4..d83385f3c0b 100644 --- a/Crashlytics/CrashlyticsInputFiles.xcfilelist +++ b/Crashlytics/CrashlyticsInputFiles.xcfilelist @@ -3,3 +3,4 @@ $(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH) ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME} ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME} +${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}.debug.dylib diff --git a/Crashlytics/upload-symbols b/Crashlytics/upload-symbols index d49594ba35e139f047ef6a8974b1d4bb24609f69..4c3f8258b9cc3359b00fec5b5a2006cd374a01c9 100755 GIT binary patch literal 809952 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 z z`FkYHpAVeBkHY-NfY(;!{{npfZ0GUsHgNtf3d^rPPTEK9m-T_0$p_*%?uEE+iu%;& zPJBRr1a$TOl^^IGL4OqSz~=#G&^v?PTA}-c-VJoM-v)p_2=phF@*?FO+ zb7i~v`!#I8W5Ct%v&KBh&);X!T1Y?j20jw;QUiDbaQ=QxL*O%k^Y>#O0RAR$KJGmZ zd<}3uKk5v86L9_xPA}lQfb(~11^_<%3adhmD_1bQ;;7NyWbL4U!39tL`*0X-7*g`mec$QNUs*u}Wb{#gn> zw*Lm?*}l7wXZsyTp6&BB@*GdRevbPCk8f0^zHuDeRyp@8pLd+|dB}@67PjN>81Z=G zktO5O`wbb7+aH!`xA_vk4!sTnpF;z#m`gC~U(3N4x7t|`U1=A8xP9unGM3|_h)ZZO zp|0lr);=QJtwq` zJDLmNO<9iZy&Ltb&mrvGBK6|$FO5KblebFz2=wFg#JFt|=kG1O2>u82B+lPoVmy7H z#QA$v=fU45U*g>$pZV(_lsJF4sYM6bj-dq-=kI56znySY;$J}ypQo=pCUO4070c;z zT;lv)t7ORk9k@rftna&yGOd0>^7D7C!U83Juu$Us{i?TscR3?*{=U_Zz$X+*oWGY9 z_=J?x;VX&%3H^@&pLR~->T&fva9$tM?@1}=%-52izf-_|zYP3=Ws+|)_$L)ZAK=VC z{({7Z0O$FixQh~>px`4fOMIDvU;S3%hk)~W*sSj*&fo81ecmdO_z&P`eHvbs_#X=1 z40tVkpNr$OBXD&b3I(o?Lz94;smqA5CQccL4#8eL4yAzp5bAyTDQQ=xXMo-T^o0st z^nbCQl-t=4eB8c?$n&^nCSI}e`>=RCh(>>xRC@0EJ=y<a=pVGf`MALC5&Dbzc)Vsk-)b%O6f}Kv@m!5Kp73|z zI6lGc!QX|O^0f2^<0n?gJlDhcRReqh%I`yZQAt_9V)Z@<33hekM($J19WfM{WP_z}5DTX(Rd7_P^Fv;%fUZ16Si@Mmx!`_VZ1^&7`mJOD5u{ z&Pu7bI`5VRdLz((g-Dkts9;F>9tAbIZp0)?-R*%6(@khi-4chrTkx!%i#SYS6>T&M= zK=?gT*2D8--vU?H=}mn?@~iKO>efl({GCJYSN(zW_YPV9P~iOi!`aX?7C3)Tljo-s zfb(|}S^h-eYJ6IOtMR!NxS4DuuCsCwKeG`(i=c-%&WPB_1w9+|v!HW)=7IhW=;s~E zi+ITgeKY9l{8|C%dq7vm*Fw;bg8qvlU+5^VE7khg&SOZFFb6ZR7upZBo+OJH}lf9_UiKa?Ra$_pP?S|$C)?OhZm z?Zf`(_uYxQ#AZ}ZQawCaj%bgg{6?rpv{7t4jt1TD{JgADIivHfh#pe^xNWkX#Ykl> z4u7{xy3k)d2gct+<@37OKC<0SpeJAFjqEFNb^Of(&c`PnAKUhm{AxVT?+?31OMSa) zGMx!~tMBPs30!?o-{S+MoW~Tutp?8DZRK%x6L2+tcL6t(Erg#+5T9KkSACv_{lfBl zg3stYlKm15yR%6~XdT;8U{mr)!I>?!@h z@`83c>&ZB$LLYHok-sxL3FVK%uBx8jg}aWUfC!1JakLw_8b>V#x{jl^gCx%1)n)&8 z2F~Bf<@bj41g^%#0N`e7o3Ldm;$j{AJp=9J>$x(}cY(f8p^LZ?$7|NB0DP>^kH~ZT zyG@jS@JCwF_p)#t3crYr-wVWk&4EAJubFwy{w+lQKaHObq0aGR-Q_G_YE}MM=qbi= z{w{F{%1?s*)%fW@*meAj2hR56acB~7HGbv+SC5NBhe-MC7mkzBz|}ZO0&b=@=*NmC zavZ-~9EkHBmjA!@yNENf@pUZwqXd3nf8_3V_Dd1+|Eb>__ICDr#vW(+QmgX6?05by zH6MQ#M@svvexEtiwcpnOSN-leO!BLK4+gIK{W5UwpFD0{2d?`4PvB;1lJL71{BATp z2)_uwvwZIVtoMK0-&Mb}KZ@Z8_D9ZMXTKC8FZ>~{Gc(?XA2pd)8!qiQ130g%8428` z;7ft?cfdy=E}%P0NFrn{5&zoRrG%6_)IzAocGI@c@bA) z3{~d=kHgOVy?b7F`$)8m2QJ6oMQ6VWUBt%US!X{>)Wc&n;(k9;{TL*O4>N0L?F~EVYzI-b*y4bTc8T|ksP_#+M#^@Fpgx`_*$8|Va2{_C z0$1(uA?&Bx?R((E(VzG|%Qa$Uy^jFr_bk^3J_b1J(*$^Z;H-~7aJ4^m1a77_i*v(3 z#PeFT=X2PP&l`h4-w3+;e&$fncZ06ZuL%DMS=`P~z{lnzxf|H``Q1H%p1kYAJ5=8BE`G?%W?A98d;9-CsiIN{Z$z_pC^0@oWE~hua7L( zYrN!td#%iKfB7R(;_m|I{`C*=Z3=(oB+0*D;jal?jl;UYKUVnf1+Kjj2JJ% z;O8$;zAM_paS{po_n?ng=)#{u7LQ+i-p_t0g};bJ-%1WU`;&3u2gmV%?H3Mx1zlXn zl)@i8&%x#2Tqo_$-vwn{gWf9t1_STbM{*VFgjsB?ePeVIZ{7C~jy$x_aKI}leaC#DXPOl-)DPITV<9K0y z(D`^`)bC${oQxwfzN{a)jx)B4u&1l{&)h(~Rf8S4-%n1K{Zh5RB}L+@{okG}an=4q zUy!(J{~N$n`?q{a@~ieg1YEWMH4l{__-Yj$`KU23+kw z{eW|vGyf3aYX6A=o&Y_$zmEg1j$7%#&Ez+6-5!l`X%fn--<^m9eX0RH1@w6a^bFA7 z0^Pf>?AJUlT0vhAx;o#S3Hm+*dKTzK2J~#u{{~%sj!%p`;<}0LSL0o&AN#ip^6bAs z$g_Xak>}%aAjuNjR`et8PbKI_+@EYmo%>bJF_{7h9&a=r=PK>+`^0@a#C71GI9{_o|C}P*u?u$Q z^Rt>$C9aOgeP5NhdY+UwUE=Dv@+ELH)h+tA4gJpOyg3K-U!c!rw3Ek$T+of)`@#K9 z)F(Fno+jHX19oD2l^NJg#JPxJ|Mjxp^Y~d~hHPhJoG0;d{AJ*OL2u?i4!pf0XKtpH z(@()mfu{gxKP`S;^1t|=)Q8`1QGJ%gGZi`gfY%Xiz)p#MtJF`*$vJWNxZwiA9@IBRE`i=WT zKIjKP@2k)YKtBe$dVL{|b0W^ov^#DbA9F2X+lZ|grq(cj~=vwzLV2P(Kb{o~%0{{4Sj|5PPD z^A$adkuOtl)}Qq=im!VRw`&kjaGS?TCBAG*d>I{QrYZK$KjUm~md~k(4{?n;8G7*X zZyD^X>SxK8cK=_+H;;$v`75`>{JGTMs2!1@8`KjP>d~>rS*=J-%*U zBJH8t=@xJ^ z^XW~ONq?$-eto&b)%NcKen-3ClKg7BeStsnzVtu0_W|Jj6nqNst-uGuUWb6!2hQ^o zbyvuGZy`>2KCUrvGqqdv_Y%a@C6td>;;|I;pFvmW14O)u>l?1$Yolz>e|x;+I2L|( z+}OWQLjM1?()^A$}>GzFd#>>x${icIkrSQ`-S@JQ{72al`ZQ zd>+Q@`MAB@Kcbc6jnRD24cNT|`uTrzcRhuE;(o^grGNYkJE-ex8n2Ri^Z3E*9&Q0w z*N=92Tk@;xapnOpM7=yuvJ|*Ff3zC7nRL}{(iGQyDDP?=r#KF<{0rb?z5mziaoFye zus7R1u-MuD(a3XL+^fXJnl-Q&=`J?a@ACzQKtj~;87vkcNs9&6CwAv)& zk>he3?0gIM>I}Iry(9G+0Dc}v&jKF}oa5mOv?Ccf-&el?T#c))YhB0H3E*m66#-Yr z>9^Opj<+ko&D3UbJn%yN%!YnpXeZC7_<;T<=;}HbKhW10lsAK(XHZ^@g(5!LZYRL^ z-^OQ_XdCS!MjSVe533R%85f=7)8mrN^SD#d`v>DV{!pn6avXJV{LS&N-pBY2e&Tkh z=NI;RE=xV#)$?!LF-d7h9O`k@-SM|kJN|Lg4z8yF^4-<*Z`(0PX-B}fik}@DLBB;i z#IcBv-#i{v&5`{{^;0+CW-23e^GCd&F^G5er-*yUjrGieeynGKfxbp|FghNtRqPP> zoqIcoG2jx~!Q))AfgLUaSC3ai-<5VVlPsZg0POQSEms~l*go-SuNo)kfUEZDwBFf1fv^wXXI78rM)qO-^Po5D?^WWu z9skxopDFgqFpx_w);H0QMEt1s>4WyF_BjAtwNKOco$V9!AKHiYFM{5zzyFoH+ebYQ zHR@ki6#HZw$d%TS3$KmtM-oV=__(0%|6nrG`CJG)0yd`k1Hx;-q`U}_lBJjovJ{@>~f@cALQo)x3 zKc(DnTn$`}tBt_TX!lfB!lu+(5D&DGeKVh`UBxoPd*RK0(~{;>iglcLEi@Y6H0jz>%z_)j|aiW zaaf2v$KO@tIqqt1milnKJ%~KVSy$vazWO82ag~TX$J0XOIgWNA&++pO@;u%~lkQ^s zV}R6y`+FJsIrn$#56%6udg@H%Y-;0$0b^cKK2tb$qRM5O#`|`tWm{eSv2| zK96USz`s$(q33{KQSjG+uTtc^1N<|5pO@{n7kDe!ll|Y}1F2^)aMs7~ki^yTuQ_lt z`9{Qm4gGf=^icb^=)dARjpc6zAGiMu^4xCDb9*_@?fee>+`rWGJ&vn-OVqF@`9)OHtA|j^+6J^-=J5Qsi-Y z?sxeWoX^_-jMOXiXW9NTq^yUUiuQ=-Rey(_*&c0S54Alt4$C-E`$co$YQN}sMDnZi z5lexq=Ob5vtM}LzI4cEirY4Ix%X1TF`JnHB{OcHh`230EjO#xHKGyU9>o{XS=PQ1;-EfYx z6686Kcz&KELHJ*s*IZQW%JiQN@QEv2kF(l#*LV%!pGQbK%fAOW`;&2DZ%4iO_`~{e zp7r2yo9pL1*BgL(xIQkQSXb)9DaRY9tS{5qj%I)7`{qX1m2;H#mj2=FA8s$F+#fr< zCG~1F5cWFix*vHQlep@?mB86vY~Oc*v)#CzTY9wr4K#Jf8ly$EiTlRcxmaj~tg_WilQ)E(88_j?XgW zIqv^ge;|J@(;|15xd9Ii9Tp#CoT;P=TFiOR- zNNiS&9~HfBThHTwEbb9-+u2Wm?THviM0|!|oUS@Z+NsuYIbJjep7X2Bp9HQRkF6iO z9$$)pbG&o^zX+V|%69k>INO);-+{B88Ta@^*30&0+#9$$zSIM5rZ$V?Mj86A(fHzF zmgBe4_~He6GsKrVzW9LN!GP`udM^XI8T1hb^oouzZ0AJCVf((0Jlk~*@@&t1 z3qQ}v@tTb|<#^5d%Qs)SGy(C}gKX>OZ0-sAE4q#AkDJR>FyiD-4ppn~)SKl-UTIXt$K};D5Auxq5AzqtS4>`Xoa9R}=#MNfGNFR<#!0?>H}dk5 zDkd)<_4-tH-EUbx^K%uGXHJ%U(Qf1wWK>LE^hC**>qegWrHaWboK!Ks=$9p5k(+vR zz!zpPp0WLktQD)*=M~9kgFK`DW`50Cp3!(^o+9~-=&WDp3}<+bE%1D}x`#*61ld6919 z`Om9Zd$Yio<3?Ul1?8pSJH%yf zg798q9&e1&T+|y-^X~06Z>yMoHq>i%BQF>4p*7Nralh@d-a0(VtRzv!Kk&#b%` zkn7_#U{A&5*-&qa8+rcwDkd+xg7y0Cm-4dR)SHqo`Fv{M-M`Vwdz;t}YHB?w}5tO7Y$iwY-|QedJuPO6PpWamiQYrru)kaXF(j?qey> z-{<$uye^5k}nc`M(xPOb6s9;_-uHt)Ld8An`6Ll z`&!mp2D%Yn>3PX#HIT#l=AV^(M)AaaStlhQ=Z(^oPb()f`S?)G$7LfeK^lnpqfDMh!n}?@ z(hOyuCkXQqaY&1i2H-l|inI`^8P~y~NVAcaAPvNIV!siEZ$Oj<} z#kib})Cc2bG}26@MM(WI9%LXbKEeE^ z*v$Ih^5@)^duC<#BnYbDrsDo!dAL zDq60hd;zHM-|`3khvh0-5A$)V+KF*aRXW>|>Hn#Hxjd&_59igC=|=T2|Nn~bA^728 zqycXHVpM-capqG~qxPtLMtP(1{z|(z?t*}aA`L?tiBzqJAC&Gahv|_9ILps5pmX_ike_eBS7d;*{E`W-^7~EgX zGQe4Wt^wUH-z?>4E_AJj%>ZZlfs0(1WBC?*FSHQz)+H63zh?Pin0ID*YMRmm`fqdA z!=~ibax6bz;VV$`@ja#dGRzzMVIEhNr{-CHpd0?By`_9EUy6BC&KspH-yid$Mtrj& zKhO=ITAt;rxSF5W$65dEBhG$M`2#+bbe127yvoOUn=0Q8KbK?qp>F17Blh_s2Xe>uHp-{7^Uiz57Z1&8MVY1CbiZWt`^elkwUb3H8IWUeI`>zljBCG&I2@;Psm7UFr2ILymrx|yHJ z2c6}YxZ&S`b=NtVSIKuXzY_U}bN|Xm-bnv5SRY)%^DMXSZl`R}S$_}AlNib8`H}y0 zUgSTW4>6htaW|jA^BDi@`3s|Y3w54Cou8=ayu|-{9)j1G+sv4sYbMiZr1?nA%_VL{ z%HLP#@4ec;%lQDxBUQhNGFaqPuqu?;0Ht z91&tQ`97D;l{8GFkh?3$L?nv*N;-i-m1ycMXx)Mv*@L>AoAi_E4R6K-oT?Yn- z+y4zD;UXuh;eUgJtu{}R9Zu?bb+wwzy(8$aS9sU(Zj|&+p-B^BZxU7cwmSwAy|+oE80c^bxf!p65UU*8T|_; z%MYRgej(9Km?t=rWRPV8qRQn7@eka=5dG+#(7h509t0eo8YB5b7t3zpn1{tIZ8yx+{^V*W~ly~{yLbC{2)4z+Q7jgTDz6|7&-~J z=!Sl#TveSE?JI37^bK&NvC*SjipquB_PC)2Q78-F>536e4>}2rpx#Hlz$ByE*4l%z{S77ym*Ag+%*_5P_eFH^nci$KW1XZXd@UW19MdRhK!KBi_5cyj~)F3y%ox@tT zN&F4wp6x3&XlIWDp`{2V^d%WHBXw^;+j2-4)xn>^H0HrV_JK}TR!@(MJD3r3_U4x} zrrv!RRVnqX?i2O;0)2(6G&V7}#`sn@vSvB-N+f5wTy~N+jUNkmPh%0|0 zy3@&obf5SsnZtWiDhw|6auND(!KLq{t6zBU2r+2UX-WCtXu3HQ6qP(`Tx?XTCBYJt zX7L!%Ak`xaSYq1P2uspvj{yv%TGC_Ulk|L4R9bpW?D(kIxbabAC&Z)@*FD4*)h{9> zIVqMHEfInqoRAzlUKS{)^h`(|6_Wsxt*n}@w2G~)hAmUG6=_>{=2!M3LH&b!heUM` z9XK?sd(;CYwR=XaB_%yRnQE_Z%|8E++%)3s7cnSlv?VoRQhd_b?y0HCsn1v@c?@W% zQ~D&w#w5f~wv6s(NsCR5*9GWgp(>T^nwlCjDIh9}ggW#0h>1^_kZK7hn)ETg584y|VXZpn%4u6_~W6O#HQC#QrY zCnhE*^-UgaNt2BpAJQY3Bqmq}TT;`=zIOABj!#R8Nso<-5<;S$gMWwhi%4%9Fe+wr zRE)4)RFdWSs02&W*z~w=ZMskN7|=*qcG$pPMqJWnLQ0#qvRsr!I8Bze7j`D1(7?fJ zDV^XLD)AJD4YImMMa4`c^T&)L7o<;$nkbt_!D~uDx?SX2kI(G=`spJ z5@OQQ!YyMgsTOjd9?XsNS9;n*KBQ0AhzLF6B|k;7)h{n=+m78ftCqKY_m&+Z-MnS< z_RTxC@7}g0-{h6GZRa+dP0Ke0Zr`_aSJsxDTl04B+?8(%+esSe#wiynLbq>BQp{MP zy|w5n_oE%#Z5g&aEzee|DA;frCCzDS;oXnNJtmG)|ypbtkm~Tb}^=q@a%G~e9czs znManiWmckb_Rb=`Bl`D?u%yO|(K1F3vkk5Jzp{3B76^%pNsWn3x1>f`(me+3u@zS# zgKe`FxM=c_Lt-9I+CRip=Jq@j;H|)hTwH@2Ym3NjxIO{E_Z?*ktFJblEPq#rRhN)Vc%|%Il zfEU#iUFSl1+xOZEJVn4|nRZgx7*U_k&l3VRgk%I>H>ZZ5NK9-2Vqs({+;=$2cSnjn<8ggtjgi(}a zxd=nDdj$178n|dg9uq%yf{Ym9gxtI6US7>{9uAO z0?-j(@4&ws`>@}HgaqonE?gIGiJd^l=!q6Ot)atML#vCPAkGY^bljab4vSAAC)|k- zj3ce+uxa(N6?)oAJa^I{yzNdlvIE&I$)XSa!f09c$i0&pCmYn%J83imQg2P4)F(bI z{f;5W%U0&Xe4zsehUwiVErkxI)QWmmD@N>pT(I+DN*@O6Tf;WHI1sW4!(1qs9G^r3 z8y_5k?&NSf87*~jXb^|l&=_%6CEQd@gGh-BF3~M|B&R0E(Al3j9NV(_Fmh*=z37A^ zL+_d8k(o_Wq;Bk#p!2#+tj|Gb=A^AMJVDvi9Xy38lXxWB<2R*3av#WF zrkU?-F}KHBY-ilHZ5JKgX)NDHjoQDBM%r!r^DBjJ%dbqi{AvQq*7on(wx9lq<9D{U zi*iJ8A)SvH!a>=mSruD>H}fjiE$6oumLFS)9dp%u+N++qrsjzVjT)w(BwCBqb3~8S zQmujg8cbYXb)Ar&jH@v^wNIarnlv~jfeva}9;sz^)|hf8g~w{ThpHQt^gNxSMul6_ zCM4=bGX-qPh))-CvUDDYE4VRqvMdPMCf3EFg0SS|gs|ikLARCD6X?oLKsk2El0Bx|rG*%F@ z$_bWq9x9`f=xjSZIWayqDmFPqw@Y?8pAay_5;I;Dx7lF_V+%r#rw9xEnp<>6GO%u? zWExG0n(J97C~EBF*aYPBWS$1>}HmDr0(*T~5OB9z(*!ZIwZ%#Ow< z#iuiBtwdF%C0HzaEN52I!>&)Vw7blOCMVM6jYIrpOFY6NPQk)r(&K2rW`=kRoyW_I z>@=aIO_x6@EjC^6OgSPu){>q=7o|ka71=T6(Uw<9i4N+I)HuPKFIer)C=j{C#28)c zLR|`7P^Lf7t6%?a-8(!k3KR*Hy;UqSqZ49AkJiJpL}t?_B?`_`k?R-P(~_>wjfita z{aS=bWrCDAAqh2ED>ElE^+-)l3`v|Ojd7~xGoozV!=+eukY}wTT5fM0>yxR&3GBkGDm0|@p{cZ#Ne-vkbPAM4 z;U}*MMX%`jMrcK)@n&8Pu7h`0irMn(L1%jVEnG~BS1F{MkD9w@}BE4UX^h%My63HCN zqaER50mlkM>%&-Iok5%i>V_6Xj7%g-H=V#sMSY2uL{wMiqA4VhPAH?2pHGs;uvR5e zDXGcn$+5{!dSzCXvJ#Ug%Aghb6!IFK0E;&0M}cesQs*NJk{%+^qUfA6HY!OT0jmlF zMa5>sMA^NaqhrQ1Vnm+RE;F#P+wS84|F<`=+(p5^7}x%f1DJ=ubwLhb0aZk(@RMC~l#!>N! zDS9*W1PCmhhQBCFl9&k7$Mt;20{R?{y;y-GN%xkWROleF{4iG}P>Mz#MvFy$6ixf4 z(`1VtvLymh8Y_l9n(MSkk2o=i6QC$PtjoOax%;%J@K!YvKE{6F$rRbNwAh#=T|$;l z)h`x_H(TUVE#fp&7}cf|(`iClH?f{evsm=uCs)s5Y%6Y3WI9{FajCY#^x%X0v?-ean#JN>Ih(!Af$ zHfv{0g;h!_1vRYOs9v2qjrz~md^dR3se48ne9ZK&>4I4RD)~;3> z=38r(Hm_2hMy+4-j9F%yS-E}tUI8tC_dMb`c7-J(Tde%9hZPUKe zmT7^@w0Wj^+9@J#)b?oIs1g4DQ%twDMvXE}wF|WIuWR1bs(Jfw(_-4y`cShR*1T)n zfB#YKb?r~n$S0dMSXXJj_Pyz-XQ5|J?{>YGn_f4yZq}@3P5<$qnC5B?8Vn!az}wru z-W2Vq7W_!_nc6xn=Co($Zmm|Ex`aQur1C?4ovV2JT=uN{;CS!j+K}XjUejJ|vOwEi z>2=S|+7zwlERC!vG}@v~*Bafd^s4Eo)*`pk0@GpBx7yfOwU=jVeYTlmz5TtteSXwV zc`mQq;62j4Zin~CxHTH=&}M62Rwmm9>U&_sKU($bv$R=S&zIlQo{Xq3{`G0lr(KpN z=xv7h+Dz|w+TG|cYL42Z*|bKBO_xmtorFpu)B#V?vY(%#W}_9~>1Tx zb$slKX?(G1z1AvQYf_*+^-P0proP^_2hP-vYb8~Fs?^|1&v8?=Mt^wD)e35SD0HKy z(oVq^l@#2f0kQ(<)%a8GYwb_1@q3lqo%C$ic#r3k-+9j0_G-s{r<;a0+n}x1=6S9& z4T|>7GcD1UYmbNYKcH$NkLZJLj7r*Y#p zm`+u$_OWTH=jqDg?_(QGBhH#EUXLBAG`#&Qe`yP}Ha}_msvh;Ovaj-G?QpH-ruR%y zU3Y4WEA6QKx7Us;2R)Z)2|1?bk!7B>7kmDq{iXfxIoorU=K|ABlXrtUZR!+h<7j*A z@u^jW_z~w!8%(k$PPb@pd!93WrwOvn)PWTEN=rTMnPvLew81lJh4#5aZmHI5t=8<8 z_K1)7l}a(wmYL>`mo6JL z`Oil2EdFiPQs!vWJ=-1A!f$H5SDPXinp*et^?f!t%)46kIa-&e{08<-+eH!8EsPXD zs*OD6+15LHj^=$#>sh_JSLa94p7%*BHtBop#wuTVFRMiDwr>-bYxVAoQy}%qX!oe( z@%tE)$9AUeF{ie2uMFqD0>+(aWicZqGMS^6B(~a7X$Q`pBze z-bdk|CF?JjC+oNC-&*0{Mh`xcJUjh)MZX^uc|Q`fWBoN0{y-)FleDK@pLt4q`bfIn z{$rH94_VGpzZNoYm)BXz4^#NdWP9!H`>~d@{%fQ@cKRO0zI7$Po$gKX&&*0%>0{$xepfr>v;m3%|`$eN>klcMi7#lK0!O#kirc9iY0=L@8L?e@D!6ymq* z`;`(8zA|s;&yw;Iuqo}EuaqAs+h>hj9@!<2kaslPoQ9+K_1=kHbI zwU>E&`?o0c5G6lU$q!N57cc9#`_C%#cKHjGd`%fIcKQeUcoJmK@00TF`7fov?D7}L zc(K#hD*4??K2eePv>dTvAuuGcqd41^tvEHx991#J5G6%^f#e$3sCC&R*9EuO8$2xUbZRacPshz zR1GO(k1s!|k3GLrp%*Iot4cmx#*e-HVMX4=U#U|5C8hj(6wm8u7yV)!?Gdzx)BX(Y;vFMo4v!exNvwVl9#3gQ z+Qm0o>(kzVb`t5akoH8{X{oKp2-*kJKAiSvY41aO0_}0MkEQ(>?eEjRg7$&5Pp4fR zx0chsl=gRMe~b2dw7*UJO4?tbeJkzzY2QHm7TWvMo{14(ms#&nY6!4`$XEaX`e&87#pV2{u=G~ z(7uHBMzqhOeG%;x${rulK8^N$v_DV#6xt`#Zl&FqcJigiHriLyPNC(ILHnz;lN&vv zXx~fw9@r+6!nuO#7R(r_;Wj_QkaCru_izZ_s{__6f9)p?wJLqiDC#K8W^M z+9@nOhS5Hnb_!wrgq%V{KasCXX+G^cXn%?JNwhyl`!3p3Xiug+kM<8}Pow=6+Fzty z_;d#CAJYCh?T2WeOZ#lvGim=nAOHW~$K+-Yb-k(M>RXkDTZHP;4Z5M@W(hHI(2bE; zb-^;hyIesywr#Q_iK#Q8l9JWyQDg-9argkOes%9L^!VwSBtn<`pqkx=mxsJ@JTJAul?2! zJ@P3j`w}So@*uf}h!+n@BO}VOBuXw=a8r0q5W0UVO;uQ5u&#nmE8ZQf?wO`9Pjp zue$DCrPCpd1~pep=~Yf%kgwttQ4Xv6RVrd#9$+iH9F6*x9P(W~TBue*=PTnq?y};H zNb-R?ETN{6#KqHjSiq*PfYaBwsUVicsfvU-uKJHE_ZOaibiHnk7p93+UsR^9dJ~}` z*4o-vw5i%StzElw(VElBI{UIaX)jmHz(Be4(Mm~h{p6;;KJ9J{`oo#TARg;f*0%$7 zEm%0##Y3CqL$Q9&#Tq!K$mMIuDNEsi%GGxU3-z2A^-+K1MP?4`-$*y-g>Mk-bb`%G z-RL4rU*kq8uVvGJ$_o^I*ubodub)S_sOF|AwU)oi@v?XC|Ir^bvl*nU9<9HnpJEzGY!A>*Q(x8p&?mP%Y8)UQkw4`@-zt!p$0_28 zmV7itSUJOLHtAD}1nHZYE^@tj7Ba4R(7XJ_7Mq;-*ce*9K8l{?e=IhY7G)+(N{^3C zdu&3AIGKKwPI*QpC!~3F9}pTjEU<52*TEhsp2MnDO9`mk>5&-^{`|$W9|qQZ=iZlX zmW?g<%sJVlQH=v9@6TWJ{=E$sw0h+CRV5?5re(f3A?v+Jv6)?3mSSv{pT_8ZG^E$dqKx{_qM zr}Chs$5&UH|JWOqD#uJ6Tjh^A)`SJ^#*Sb8b+22IjXPWKz4lFBVNk{-^Y?S3T75Kl zUxQx1?O676_w7&Y3t2ELcZ{zq2Ke&&-{%(68t<|6x~e*PHTD>yTGx^xk)F zQp;fj276i8cRf{Y(4J?r#y>p%&-c?ehP1jFaAL+U=jMOslfUoS!!LwQEiBC&_wLAc z1CCz#=$-HG{i;Ea$<^ncvTitey!D2RmFKRv8vXXdnQi(!yRFSjZO1+EXY9w;r_(n# zP1@h=;44`tJ}kaGzEgu^J-seoyndkBvJ1JmUKB2IO4HUbvu^M?fCeg_a7-PTpkq`bvFK$PDA>< zwDY0W3(aX~UjO0g4s&b9A4te~=IN%je;@zV`k#XjH>_6j@Z)Va?w`BwmoAG=-Z#2k zgI4X55B3WV?(*e`#i@^0`D1+M+8uA7%s990R;_V=osB$p<&zp2J^X);J%8qM%Z|a3 zJ8KU7rAqB58l{f=qUrC0c7NKTa<7-0o;w9$T^;PFX*%3Z_N6r4=+#iFUZk7D)i=7H; zEN=ek<{$Ph+A}>aDfa7&@kjSP-m!VZFZca=DEs$U58do?t9{Vfgb9ml{Lmqx-O69$ zVy_*U_rWLO)$=cglr-J=eSF)?GY8)q_e4qaze0XG*m;-v()nwBhwc1){38V~KL5m- zMavuf^Ox4-?16-li+43!y=(u#GdIK64Dh)$`SA54-(T_`9lPV!dw<@XGUUa%7kh8n z-?dTSgNH}GdHcpkU;ch@m)BcYcdc6M*P>GP`D0sazBppXxq`5_&)5F*=A89mof_U~ zF({uFy0zN;%uC_E-B*n-eg0;rS_MB|xE;Bq)83rJw&#-izt!{iKh_WNoo$-kY5l}i z)t;@pyX^iMXQG~~GC8+F{(-e$Z&?)5uW9ABe{3J}-NF2sQ(g*6TQ_x)_p?VEuJ^TO zHJX3n=bx5Z*Y&>Vz(0qBdKTBZ9rRP(z)#N2T`+Io?0b`L*SLN)C(G2n_EYzJ_Bc{) z>R&fj=NwP{uG9RiR+-k8XD!#e-v3X@^GCn_;YO?c&*xoCKJodl{m#`}IQqoZYgw=E z^_?2~{qxm(TzI$X@xQw^C|uETQO)q^(AE)QkM`c``|w};_xUC*+&X0K<{`Dm-8?+s zcW}K&6Bqp4t9IN=m%LU!^i+?7?ZP*&DEP|sedv^ui9Z}!v}R!c=o&Szp1Zf$_DICT zv%m8gJGENe6GinreOEjhk(8HqWccUx2h=^C_~ti%ZJl@MsgHwqqUW;ayVhPAd1U&1{XT9! z{Or76nwu8CvoikeO@}vL{_NX!)~@3R+&FMX+x=R8f@NIM!$S z(}L?hnmW!LbZz6M$`N}myq@}8Y^%vlFWWw8^X1_qC0A!o9JBnF_b%6c;#m8_h_zqU z-zraPPEMU#H&e^U;)rCkIs=jddiIC4wU?dP+Nk)SCp`=HeEI9ly03M#HG3`V^xT-B2@yR; z|5NLp6>G)}ueJT_Rzd$f{L7)}O{u;1)~K5KMfChn28a9pJg&HKN~40LX9{Ocx>@l4 zxfV<6jz6@a(e>LmY97k{c;x$Sa)-Q@6w$kSV9>;7qe>f@2Olr_AoH;`8S9_U6)2qkn3D^5sZ#gNBr z4^(e;`r7#?tD0_>t-Myeb9&pY!;1F&ylhI`-xpfk+da3>BQb5>{Vrp{uS;GGy1DO@ zcQ=f!`JOH2_|o&2OaUEBQu;ht*YlUOmjX)t<7|ufz4Y3zxBp1#GQ7)I9Rruv>ip}y zbB_kS{qqyv$LgF79$GD8ddjXY{TB@HIK9$O=jI)o@Zpx-J?1r=v#<5O1BruYden{{ zz2KYgr&jlUVMdF@L9cu=?>FD)SMQ73TEjQypzWLIhaTR!dC&~=fspyn)y_)Xkly9Z z?`wUV+Gx+wHwW}xHmzXrmJ8$l$^Yo5`)UQ<{=I&ZxysJd?}x4qZc(}^aQWHayVU#P znY}-3Jbfwo`m*;TdoJ5Q!LL)q#+=^4;eSngYRZR;R_$3eWAGc^)%MO>|KZZ#-u4~; zUi%@QYc|xWv1wPr@Ecb>i-&dYH~8GXcMn&Y+U1|@aeIF5er@9ItbS)2K6%A&+mxTy z*FXK;d;ZBsn||h1$@lMxZ=Y)NxwYW^KfO+jx^F|*i?419{N_r7zYh0!dGHq{W4b&W zA8he$*?g>R*}{8UCtsU>{JW%(Z_HQgf6{nj?de5l*1kKjaZq%J(19zyfBeFbwC8?q zJATlNr%rx)&okbOHqS_0aq5-n{_Cf|=y7_`*p`JOOXh5x`O)Ale~U1i8^y21+YD^C^-Lv9~Z_n6i?YmYgASZt zJ-^;(x1L_O74_rtLvA5^dP=DCNT`tZ=nI)nZ$YJ1?TYd61m z>!Xk3Z&jE4KD?AH6+t-Ho#g-U_Kc{l|EZFQ%rh{d~+NTl)61 zFBBb|6tV1`*gijYpSj?|>ZG%|dpnJ}{LPt5gMY2Qw9}a5=Qcd_$FU(NTX}5xt#6Ab zUcLRuwAYu9{Vrq6x#ka?{j6=jYPXwQIngEI+qv~xX7%)V`RXv=zw%7s9qy~SuYdIT zE02A!ch+Bx;?K7T|Mp6=QU4En?;RJ_@%@e8-KAPlmX5G17VHc5*cPy0S8Ue`h$z@F zf<1{8qZmz;SffTkG{TKW6S2nxY(WzfHL=8~0n`Lyi3OE4BG3EWnai$7lF#$}@%{XM z&x5bmdS=d?IdkUBnKNhR&b_!djn?@0+~$zhxXuUqr2YLJ+|RY||H0`6CvKPAnAH8V z_y0<}y7Hp)zPWpxhIB~R7<%`J@$b|2h|f?3va|U+4OX)UCH1{Yew|ymNRUbCNT5XpdJm~AHUN-_WG2aWe;udJrnnzSggyx ze#Et1$k7n5ZPUw6u8aE6U%$&K*Q;I3WTz%&AN(2C`>Smqb{f5><>2qjHXR)YliB~} zqBX%0`!hP1?b_x){r4g6M(x!dH`*Yirzh9+B$^IT`-R5;X?V`- z)aH<$P!peOO&13*eikvoMok>qKT1(K{VOk5(Q|wDk8UZ@ziP3wjLG>$bHT}Vt!oGvK9 z;N?=&&)?v0@bmZg^Y?2z%B7}%dyA}Lo?i1aDTf`Gj)3C<=Af7ZTBo& zRIQs$gM~ZRbh|UK)~elEwa(>sy*wA-&cQpsBL<+vsu~s z1!2W!?lzg*BRV>4O6YqZzS!*Z+Z)H~@AVt#dHB)(HX{S?@5xkaTvM#}@15JSwRe1v znmuBU)EYH<;TykSvAbNomjATB7Pq@K_0tn|-kY(gk+h}z`G*HjEm-ZcG5A?^(fP2? z$t_MD-#Ih(xPNHvypV;)Kfc;&H(|}_)9#yY$Di?@+}(3(*AsghdDpwUVE4Gx$z6J7 zigo?E>1O**tLM4r*nm3Gjh20T>0F(}(*tTh93FS>XS====WhLU=Z=C4{g#Y8t=6an zReHiFhJm?zMWh{mbGh@3%C5@~l_?g?8f%Es4O}sb{HZ4C*+!d)(H$qrGR`mag}m z>gn@li_r5YSABJV<9jnA6F+vo>F(gNv_;0*(i(Hc-Zgv|w!SaS_sE*PbN{|01Aoo% z_&C>XU7za1C$&1(b^qQINpC!uGcE2!OP|5_H*D9$gcWZO-eGg>$fyEu@18y0xwY;| zV}}E}`uM=w)l-9Jo$S(Z#n^PAXiK~0!5vrZ?exdW_?BxngcZ;IzPMJkAzimVA9%&< zvqfv(_y2Nu|D{E9UGsKs2s}K$r^lkLOTX6^CZ89VJ^gI>iRRW#d+e_MbKgvL?KV4; zzX>0U}$G(40~d#C*3)oail>wDwoEoyP6-PRHPhTUD}w)BRn@6;!@pVl|1 z3thXG46^@mVL--u)A=(KH#L}2=Un=cTOLi1d#~9%zs9y+%SQj?+`jd zwA;)lV{2Vp7`pLML(Sn~EBcSE`EWv8AE&-fBkS#5{p{(c%|8q}oFfjJw8Ab+_w3u9 z&2=#|_IFbmmLCZEq4vjJ9yjal>z@1a`+bLM{XEX|(zjjqy|Jsfb}iw<>YwYKTgF}N zT=SRl&Yz~g`C+di!*X`F3fNon*UcGce@pMz;~npQQwFUKSb8FEe07JUfF-TpOZeO% z-W_G-zdUO1ih4I9W6LIui~O?pmDyWbYa`R&GbaoeE7cE6{eca>yz8;3@V-4 z|2p>*RkYC5(^(~|?9d{XDwV)jricmFDnr5}LsJ{OW;QBoYg@I-*^4|wEL_8!Idd#r zgX|krAs12-jc)M6fpADRVPiyMv(Gn_5pP-9~nLZ(!zN`|f zit(!p~Ym0_>^t>~28a^Em+p@ycl-<{ub|3X?G55f| zbE`9@Z!(4FHQMrYXhG;&(e0Th)oDPE3HS`B}}xA8y=9Z)F-XdGv(rh}LtSy(NcZ3O{#)E8al-u+h?0kD54gSZQkby%PFR1jQq)H*~#XVkW`- z`t=La`I@UXQKGf#uP`(RJ?3h!1bLWh{~Yw>-l}soK{)^YZSB6(=})J3+wU6t`a{lm5`)TCv&Wmmp zM0^r|B5Bo8=XYI~jH%JGTh}pXR~-N9o=fkax^63&FSPqjc=Dw23)d61!yg`4dodt& z(6$+qoX*W$x9q()d~WFNdrWyR_R=4`I|L!KT)OMt2>XoLUm)r z&pw74%FfNT|V1s_4Qtr z@$kvJXY(2juwAx)(c6<6v6s5fN!gQo zZg^yRi2J3~pABJ+>bQhow00P=p;4Pl=jTk{eYJ3N&X?2HC-lv2cX7jt#m!5LtNHcJ zYCrab&q~ccH~;=a9t7-(X>lO%;%{s3P3ab$q5ZSFW8(Ddd0SrI^X^~6cy~{_A?;RF zOs{^wUsFfDIQ%s4y+M1kt{i;4f7rA&)#JbJYq$O6-om}_-2LfVeZNHQSVN+ABzCKY zgm?do{#k8jxn@}GnNt&0Kfy06yJ35cpEAp^(^eTg%_Y`;wc+F2VDH-AuU%_Q>QRPP z=29!a`c}Ft-)X&jESo+0Va#_OL+{t#v`AwOmzY&%353?J#sMpTYKOzgC78 z7Tfp#pmw6FiMhVYFHz-=xXHP5x4F}%>iD;myVUn$?vOqVIO=u%yJs=>`o8?AJR;SHDH8RJ(+OT(B!R)-Q#&1Jco*D4w(%nMIp|N*6 zex1}$Nd2{A`<1mj-J14C-wAccb~j85zHqF2?#k1}AKYEO{JW0bT%PWZ?C`YPjLseN z2S_K5Z_n#{d$5%>vd8Y9!qtZ91tF_0r{$h{+5P!vzC|gE2Kf$CsV~o4vsyK?*B2At zXo*>|FaOjJ@4Xou-}d{Jo~N$e+u(a}N6$+ijz7L>ao2Hn_!7h94XR}|_cm6|ZPa7y zkwc?Z?sZ+4kMlH+Sn9m)*6i^P57!SrIoNlCTlI@~YkP#PYcRInh$n`+!(TQG(w%?H z=f{Dz={tJ#ZT4N}h_@!})-YmgsQKkm&H8O?7_sWAC7@<(KGy zjiJMVa!bbXQldi!P}|fhOa>eaSvRYtQM<$IEwHGmvPzw5HQ5k_nQdd;RAXgrWAG!L zTTCr0-Ozh>&+hf~ch_I*4_#Ze+qCl_>KGB6;ZtJ$K4Rp-a7OH7SS^tis3;}-i3?3}j)0*WP zg0J-9w5xxBzY@+>`#(RfI_)&?=r=QZcr{tyamS7GeOn~gHMxIx@Yi_@=MQPSY0|N? zqnm$PGU?ImC7(Xb`QHD`+ucfLu06Nt`US(d=aYMQbgQ+lYv8<(opw+1oPDUZyW25e z)BB!@1J8+NOFmzD%76KSi!GDCKDh63$ok1nGx6{$tK`pdd#_JDUs5M@=b)yKyNUBs z#zm;h>K^Eml6iYagZIxQ=e_w^`=Buwwj6Ns6W96PH$3ca9rDGTQQu8f9X@*f+b8}l zE;Jqf!*iRjeZ7V}+%aTOy$7|uzyADw+@O)x-z@5Q+3;@JoN?}pciOMJZ7LF0Je~en z4Ebnsv&&!XY%tB(;Vqj90~QC|E_-t5$hpAz-umZWx9_WzO>7QgrlbE5xwSdlaKPCc z?ceQ?CN?TD6*Rf=$a58{$OlZcCACHd>(v&jjNjo^yu17O{DRvRG;83*6UFku=L`|w=*96nBC&#z$aN^f$y2?#l?48Jh1sXYM_)K>G5Nj!;SBp zH~D?>@=5KI1E%w2-*pmFoz2MvZMnr6R{NO-EFZe%q zq~FHSmJasYv|&g3=Inpj6aU)=_s2P|Y0o}#m^9`>%gqN@_)O~hBCx>z?P~8GbbS$P zY<2X+l|d&P=e|7HW=3jF$IeIX25eXr)3N>4&5=*CB8pe$_MSFY_hZLW`@_X=JpR5< z^aSgVdgfhidm_@+>y&eP-SDiIPaZ6-x%^s}r#3&tENDN^Utch~EWPM_dcr#|%YIwl`&OrFCWlXEwm#DQM4wSJt92X{cingTywG=cWN3dF zzIXW4?L`kxd}jJX_krs-zHtS1{g*ZhoHy=i*v%ed+FyfvkNdDs|3iQN6ua-L)q?#8v~-Zd}0t8I^W+RSRS-nenr=3K+QzF*H-QTeHUrB3m`d#Z2$ zcc=R8E$jQsNP#nD9v7kc=7v-O9pOy8oC>obz|9UuSFdeiZlL6^D& z4qkV7SG^BDyfACo@v)npe7pSG zZU}R@_F3Z#Qzo5m-6Q7odau+C3;Wkul^0jpFycG3Cq`X`5)M%yWQIRZKuA!=6zS|i{0zbCsm#5vqy{nHq)z4_38Ot)v12fss8_`PWAl~ z)!h)ubdpbplK;EWg4(WpJ89nWrY0;mxR>vYaW+)*l^yWEoDTVzYg+l?dHMPC!tLm0 zLk?PbeYZSnYOdPj+&vX;JXq|;YxsE@@RYy+;`_Q|ji(M8aw~nW>GN$jrvDIju=)Fz zAs+51(3!^jzh2$b;IAJWd>r(#+k-oocQjs9Z})=UQpS{|_%{+L>@^36qJ@Lj(TAI{c1z8Et2;gQbUW_E0IU~!9FYE6A zGX5j){-wUQBRs~Wyf=A6*o1=+GYG&{xal`q}h1z%Bmq zyfsktQ~n}%XlPvI+&D8`MSj_ko%ns1N`E_C5Gc=5a#j$mgm|8kL1<`f+^q4j<*17M zmhVx^{7#S%_(yq5esX5uuTD z>5ra<#)XfsD4+IA#?Qe2csb=?;RhKk|AmG|#Kz6UpC04Liu}5tX8b~97y;!i|Gk={ z{>F@-91%J#GA?R*__WB^#y7o#M%Le^aK?r5mj7PoH#Hi6w>5k!ACijl88je(CFzC zV?yP>ibjZv{LXWJ*<4YS|EGWG@ANs*(^vA++_^8U7AH7Wnk{N#BNF%^HenEsyMYy4DJ zvV1eR@*f~yfgh=@{2!lZGiJub;g1!+&M(Z0@jJ+CP~MUs{AXqSBEsW{+w0@uYR&j{ z;QT0W$q(qt_)VW0F}2eE4&wamI6un&GrwsuWW>>Np%Z6Kk9f`g#0vZw0GH2~;V5s(56fm{{K}nZMft+!Fn$mAF@BV{6>#zXcimGLtS;r*4R7X->%@_XH{jE^-(Q?Kiph@vkM6zMY9^9ebg{e5$KF?HpZpaf&9Apb-P62_-caInBIV?Z%k?@l>yd z68IoZ|40tf6P3}w8fxO8GRp?}=C|}~2@#^lQ#pPjehPhb=L67g3!&AJd9iVk(^~b5 z9zQdD=Db!tXCm616Eky4Ed6=hzR__lCn}g$!y{+LMk7jV6~xOp-zW>df^Y_+Lyo`a z8x%7$a!BON+0hY^v6XQTXk|$O-t>>;55rH9-&VK+L-^-*dJc$;qpti-BT6y2GXAgh zL-h^xv-aQm(KBY&bT}et56U(GbUoeqFXKLp_xa<7gXMK~=3%7+f+ulHY&hdl8jgVda$n)lnk>386eele3OV;#^+E|U3Fv{UP{Z3sDE?QcZ0 zX62Sj^p^Tj&kbO5D02?x%uK6gprwWyp`HVN$!XR?9%?k;)uvZw7x2i2T<`F@Wjh$JjXeJs@+4ns zY1uyAJto^!$W~NV=CU`WZ@FyENH&Z9t>&`b;rwoMe!nCCGwNpFVZ26ym!lAW;WBVV zK8L2gh*4!epQO$#3DrPWE68jOz1n1!CaF@&lI+iuUZZB$6YW$+Q$~_&Niq1DAfIOf zgcLofbJWcp0n;Cr zQ}o|iTHwuev;gHa{&G9{&=IG54|woy6VLNFpIKevBA86I1rxQGH_$3G-y1Ta-F(z1 zp00Yvb0X?K<2-Y2=*2n6=lKd*k2O{)PnH<3osNsz%6qjyi?Qj3y`8hgK~-aD#1aoZZVrIItK2@Rwynm3G*8v$pzzhT73#P7uBW^2TdSe+K9w zKPf14l10CheOSMJK_}D~_T@D*nz|sJ*Vt(41eny2@$(jhH|=!sA=)}y-1C+MW)26B z!p6o!tJQW*<7sZ8UMs3MM=(*{=9FF_n2P@r4i%OONAuG)Db$Y}wq(1(nLSb8=qGY=o3<8mBu6q(9D^>6hv6uTL2NFj;>tQX%s3w!Jgm zA#Wb+mBu)GHk+>r-_uyTNcTZQ{4X_Ny1aD$uw~ zV`0mw=b2vnSh2GGR3GJ8fW_cV^Z0Y5A7iWt{~6Mz+C~%BPwlD^f!udGN!Mt+v_dE2SYwQd&nlEr`ze4? zCsM!QJ-{o~lXKBau;#%Z&b>KT7H>JtGRuklYZZFBmZSVuacVaqQM(J+wDM`@T z64>Bz6?En(bs>7#;C4WvHq&)H(Y9js-llYG)SH5OG0=4ct4F&22)ZVFSc|%fJs2l) z|NRx&gQGMV^;1u?e*K|=5BsruW(oTH3^qbC42Q ztqHv}*aotIwljF`K{^}hjz}whcmnznyr0QxzmGwh>$*D082d|6Y} zO;yE*_ySTo>>#7@!Pw`4F7FV_zejclIxo-!?=thr@xov^>?_J*ZGnDHD z-A_2~&>~RQlD+1och4kS#My}!n*c5LpK#TJ7CRGG4ja6QdSrw71To$PfHX$*)BW1S zlVJE~da-c3pe;MDI$z|YnN~4gptba|Mh$yVOT>rj#1Cb5l(SPW{tO(=qho+H&lLWd zt?P+vhUmp2=$deOR-R*Wtpquy%d-_qn{?#;ZLG?C>?oMdpne|KKB67|Dft;k=_GKs zGy>)V#Ujp9edy{Y@Irvj>j=u8xR6iKN|Yv=9RwYXrtNYb>%R;gr8J(mw80{uplRrH z$~yG@`J^MTNfm5U4I4%Lxxgy3RHI6Hrm>cuYOLTJG!p6H3F#eh3+MMS-~nr4AIUtY zpI$sz7i%NZBe#+K&e9s0j@Cr-nOcctzlC|V9C*^%EI?%qPwm5WnzmIhF5>0W0BQXu zo_gTPhu;KWJg&L00A=K#shwz~X}(S(9O8*oXC_BZD%D}_#>g}-(l{Avr7<$3n6^9m z9E83HLI(kumnSoZK_|rnzk(iAnWaHO%43a6(m5DS;iwY^-lYoyQ0G|2*w^R~YiNz8 z9z+LSD0Bg2UzNo8kD=FM*|s!NA1+rg;1K*sKP>=B=hXka0Ir`6da-z*kXf*e*-uAK zTOW{OFtVG5NRwUo08-t6k7zucFb2*tPvY&2GI<^W=O)uTNiH&cJx{%TyJbX5+5hTXQ}RivfU+o$l593%$?$a@oZAMQfc)L8gg5h56#HqVKRN$j=yM(Dwk~vQl|o|{RY%#Mc*yHYm_HkT{c^qdCF)cE zwgb{Q$njW`uq!V~wTtQwU50*QY;Iybqs}@#JPnLg1kSvqGoaKuWBCW@-}IVm3C85Pu?5Iahjv_ z4)PgEqvbyJu4Y~lQdsKA_QM+Y67unlP?u~Y&r2^V zY1KTvSPyutUnWbNqw#j<^x<>39)rmC1QXew1J$t>vdGtyZF$1>o+dKgVg8=e!se(g zk;m&JIUEIOwnfi!TeJp0(yPb3ILPV&TXU6t+tYN!6Dpy7YW+YHTXQ_5hrp#`O~`{k z%16vy0Q$SYt;YVMOs&16D#iYS>=yDeyEV!(-vkZGtNV-gXO7Z2^Lz8I$0LuZ~F$ z>XM#}b@if>4xfs37kKh7Y+nXHpi$xHDDC6)7blb7Lm#oG=VKk9G5Hi_*@{1?ZZx@L zOgu0ao_s70pboXw0k9C|%pbUykHI$7FGPRc=Dk%C=0o~+fo|QTHNZpP&>5Xm(73os zD}mdD{qV19&pTBZ3`AI?FT&S@V^`(Z~()$kv>Hj&0O~8+6d;tr0SY=ZB^caS#HkQF$z``9Gxhx9x3Y)1j&HHUWe_9z$ zZ6O2gw_WDVEh$^5?wHz$&6h^NlaH(oNIvrBLN)A#=8TKv4IJ6nUkd{}Qa@`TAEy!8 zjMfP4l={xRe%V%G^L|p6Miqw3!Wjq z$s5o7!*~_;FNo>oy+305QqYi$zi}S`umxykl!Ax*sVeT=5WaK`ICa5#@> zlb;lrN%H)Gyc2knE~74aiiOxq7Pc2kqitB6o_yU?j@OHPY%}vb;6I3Gs9k1368Q?) zH+Y`5o=3s1N5apD*iVj_276CQ+bU>x68{lL zL1!7asdyZ(l6Ik-`W}GTo!b5cdD86)st38KEUm9zOy&5cfHZCtb1z3)E)Uj=iNl$G zssC$$$Ahvq`_+N69p?8Y-{UCrB;IpTuEewfz1TjX06u96@D!uYmZ4UPlOe@nEFOG1 z;&?_3`t+}H=pQ<94(CB_DRHR2CzE3uaI6oG(rBcq57~t}d2R*t(2EUtU)WwtD}{4j zg8&s-%45@iiHU!@trLgx`ojPfS#l7|lTP{or^wO)X_6)E7Lz64s25KRV0u+#>B@Pv z0Q}#TB`#kl`tkbyfQl^Ph}%h)#=t4EI3Z242zgAFgwF7NyAjb47r!$xz9Di+Eb@S$@2t6Yt7A z9Ho1JiX1s@NDi%30G#4a&LQm#Kb_r@?KQ$da}_wU>EnRJn{<}nS}*>DJlQzOc8t=3 zu&=xx;&?TDJne*BZdr^!YEc#C@+5KjQT_04lPCH)XP{08WwRZKP%UI?L^= z3GAx_lVv=YC5iKz30P5<(gk1Rd_s`-Nxp$iL~m>1^BkPV%l!*zBF>TPdW%QCihVFGe7}3VX|_%>kyc%_>u##!eatTp031 zqi@LUaHIt;rvbw$`~DELUzSAA_B8OpI8#}G=TL|~FHz(Smd5x=GD%8Q~$q0y&L#ZAF{vDiPYYH`T5TF>~rhjQW*3rKu+aQcKA zdXehV_~&(SG7#^N<-D^rU4~B5S`H`6P%A~rkm7~c&)MmmGYn(Pd^utbPCE`zurr#- z*Q)IV845aMM>($(WJu>vme1u$mgGfz-XNx@yydU(OHa}MC}PRRf;^|FEEl*!K9_Z$ zFkPfs)4UZ@A~3&#AqVNf53qb4vC@mjS~EQvd3h5+Wj$(+H0^XrqOFM9QiS81>C?Z59+@P1D*8b8ZE`BI+uY1J0iC#N!<=!$lzUnB$VHK~6N zz)}B9TgA?j3iR;c)o zgQaEbjLn!nuOOY3z}ACR!+U1ZbBZutb{=Iyb4K?)(#eei=s81X7{{Fkj_C7v{v^>1 z56mnC&e($0%LZ;Hf4=@D4jMx>3c7=As{c|5%a>39Rf#~_{DD2Vamxc6n8 z{H!I@=*Q@isXk9DcBb43=~PKdNN&mW&YqiZC#YwXexw_ zW^=k1)Q%0q>9|gw0Y|dVdWZET9D4$@ezlT@_v`Lv^IE35L2-~^QggnfQxnRm{{?_- zO?H-Uvvhg;*U%Qx{tA2;WV=of^85lw<5AIuFK%Yf5lQDnf1cC-!0FEcQe5|Zk_vlo zHR6g_l8;0sWY^^0l0JtmQlwR>EV21&_CpUau0`wZYmz?aV`- zje|K(D+vw6nFgK%@pz47ruOQ4oBKZ>^+=x)fNboQemhCAz|r{8xQ8SC8)E){8#6_R z#>s5V0>0IWRF~T514v^-V|wun#ar||%~cx7%L4(!1a_|H0zcq}vD5Lf8-cwAc$)%w zJVj@veR;h$fK0b+y(FI9d07iU@;~%!(}46P_#ld_x*^>hKhj-O89Kv;E7zSjY?+NE z$*Yx!C-uh}F!ed^<8i%?cU1K1A~oPNH369p71^{>Jzi!5$Yj$>_DEkP{RYvqhT0f6 z2h58)m=|>scjGz30xkAy*7ANW;|&&PWZ*f2JU_%xc(pB)K zeTnD1*pfVrC*~zR3wM#e1s?Vy&jDPw#u!nVyHvj#YwI}4i~Ai4S{}-J#vi`}>MsP+?{o4&%dAv+?zV0Dy zLZ09T!1D9;7UozhfX*4Q$1Ghi6k|99V;O=m9gMLZgmcD$nHcMoeDm)&YVX>&LdCu3ry)D z?{gg8rFn||SUjg)0zCOkC-9-R9A)Sz)sdmoYwM&P=?Hs@%I=QPm=T{aJFX`qpXcdJ zPt{RIdMe(;#vopy>&EG}vi*SuveSK!GSCryAt33^Xv6t-Vf6Ymo%j@G*n7x6IzN^4 z?Ib+}F3(D6N4gByi1;yA(WR602j}@CVEKC8iSxsrrhu1!3#hCOX`6{JJ?nCnuJZEZ zfQp|!g*26)0K{v-S>&&YzccCoPu6w|=-C;4qIH7CD*ge(H|BV}f+FLy?=!rf<7vEz zUf}c|@_0E*nR1(0!)2(Iw#(2_N|zz64d(q4-EpBk(?^^Be(WfIq48sUaE}OlNPj|W zrkk9#I&mX#G#-lp6*~?9p60-6;1pXEGzb>IbYr{Lkyh@%m-_9!c72op{qn zNFhE{m)e*DNaI7#8}W{B7IYUv_Ds4+y~A|0@42kg5V|8KKP!U$qK~o3M7mUf&t;1?rPN+>q`JTMe6u7%NuD zRGyvJ=d{%UNp_}JdLHN`c>qUstI1`aQX$s=$9Nt_@v;k*;VhG4Y%S7J)r_V*A5CUK zI-Lu+NP3K)pTKmLwwTQ)ThL*>dsxE93ioGMKf(Ei4aO6?HHF<^{pf^o#xqjHjn2{? z(2xv8fYk2q1kvVg8IOBkGIWLg_r`byW88XS{CZ*>dteRgj@VKypB+#ew64%SLb{7b zX}U*9W2*G&9OwN#=lugC(@J}J-JG{zcZhp#qTfo~lZi62qtsfsr`^eD>hL?$Gu_wznWxvlj@-GO zeF+(fj>S339d50Z3O0f<}~kvhQ>Dm_467tyLty{W>?mk`9AbK)>*m%n;L~@u4QWX zJNeJchT`2GE$LX*!WTZ&LnCF&-TfdCMfNs zYclhXll?kNFTf}Jg{@pSm9HmjP&XfQfZ7Xa!rIFK9X$)BHp22*8>4s|1E>wejMPS7 zr41i-W_|=~qnBD(eHQ#k-Y64m%b3S_%mLKqc<8zu{4Sk3}!v!xCY~BVf`su>Q=mSOEymJ z*zk6&cstgB|FrL-b*4IKNN<9`d{|C|PSgNLe)H}Ii?|SYS{Ggb2VdES>dY$hmY>~* zaTq><(L4qX)xQP^{mb)@_>#Y%80ro${|S)!HfQNF(!;O^AiiniG0%=NeN(LYE2qx| zEaw-FwW=G97mLd-q0DF{v?=Un?1*oQ$T3Ga_BTrT_ngN8Kqa2Y55@kU<39(ay*jm@ zkA2NC5ed&OeHk8+$0G!G}kf!VbfX{_(mlL%s$9y?}L``WV@R| zNB)j@W$$Ck)D19hH7x>W1_m{Lj{`)&uw&&>#i~5yuM)84eCGQjO zNrGuEJ=^hR`pWy0jc3{rotTJndHp9ke%78p3};*XSzg{G+@j&+%X7KWnfK(PR6lK^WPUiR_fXrvw!(ZC%nxxP{2Kn8c00>J#?Jx2I{3jK>`~#T#!rKv6@J$E+2Ci39~PoL zBxBSn_c4#*gD6h)y$yb&1=HxWMpJZ=(Ug1-`Nq{UGadpC6im5K0I}W{ngAmNll@D? zN$LR5*kw9d1(=%H1(D?*$T^ihDqFDSU z_Rdd%CqI;j^ev=mUKGd>{&9%WL_DefWk6ZRfksmi$6Wwq=VZ>(MM~o=N9K>cdtxe^ zCpUo4a}e5+{9)I;#XRKmBaEgifFx^vFOo$o{e(R3i65o*^Km!m9OdDA>CEUX($uzG z){W?$rCi`hHwTCgK9uN=Thd{@CAzOT-7diKfyRz953IQdk$;Re_Bm{wWXrznEgk}n zWcwVDY?biG2KkElt&OIgz{%$gt(fjIkf(CH&pbrDM`J3C6-tZhuscwNUwJrCSy6he zOqy@0RCl3ZDu|%>#BgTO%xGHA>$?o_6~9b!kk57Ue)JZ%-qf6@`&mBlJu5&%x}OWk z`j7Vld|1DzdL>Xf(yic~5Dk3|*xeGIW!s%TOy#B?x<&4EQwEXu5>+j~DRM z3)Rkdo?-kSdl*eQMReB?@A%2{7kag2XCYLVbfU~%W#0au&es%ANg zL$4GcE9-qVE|(q2h5pzBmc4dYggw8&y;R8o<$DETU&T8e$#`D^zARI>gz0VqbSL1w zq>}Zxvxj#t)E^020r38M+PBjE+3JW(Y9KzTi8!Se;+5KnyB!dB)17A49@(w$I%U0a zFL?-FgvBH&sV9X&$*tF(}&r-Ppa&@TWPXbuH>0 zhAZ~5%Y2HMfb>>yobEfjN$JoR)g^t2fJ%&&ycqtjHj^oDg!>q*@uhY(nBU7>&-`BD z4z>Ia_IT7Q#+puJ9*Xo+AGCpaIR!)4Dk++44tHAfFwf`g76KEWxQ5u2&lyN zO%|GcLk^ztl`a^BxiS!QW&q|+f6SqNi0%6#wrB5Iz=lo2G^WcW=v{|7=mLJ^2aGWc z|2FVO;OhXd!+Uvk0m*mBYcKr0HS*LS4X^iidxgK&F}Y2ER|P$UlYOqBV|UZ<1p$a5T09W#}aJmm!@OzWO~3(hJEOoPwDc z6(z?(X(is`AnG^H$t~ZlRBR}0Ip6O*^A>x8FO6j@K$=U$D=Hj5il2>U`@=_77fPel z%tzVJQhbyu^9_;-djP7Vdg3h>_|U%8QSy`V*#8qmUzD?8IsUC8OJia8}$U=j=(#RD3{Lzs9wfW)@Rbe>vzs+?y~;ON^ZQK z-Y=>JdEzI}Dp@tTZHW>K&>iomYuTBN?-KA6?3UqO?h7p-%ir-NUVp6>Rq@Ow6u)BDPyhY+ky!Qbn`-6u+<8c6a;z4+Y zM-Hcz0G0S8=XYzNK3?K%0 zie<*h&{-M-D9e?{+MR?v@f-w5JZb#KBdzcX|JBTk>JqQMGIW-D1IqSsgYg=QJn`xR zsPGzyw8AUlx|tW%C0-q5=q$AZBwlH>zl5FxkSAVE0cng#uFgm+I#2sW;pHUPC7m}! zIo0)%;j8zINU6nJqk69N9BACfkUH-@)}KiNC@nO{DPdfiVqn;dA#2&=dI&I z`cNKzU(VaahxDYpC(ql)hXhhy$MbgaAzdlofamSwL*8KJ9jU&W-?tQeS-H@hLj#9x z7<_HrNmZqgk7$6th9$DJp3>u4+KbYGEbT$*`Yi2AX*EkbQMy2o`P8NKF_x}P>8&hX zgVKpCZBOa(ENw&SK$cdXN2}1U|74vzyM~R^w}3R}xkt_Goc=70tB`UBWi-}#{CRM2 zSmX7nYP)6he(gP8?@}oFRJ=!kd@9zmy;$3}Ax*ZBB}1Ig%g|BU%<-EztZWUVJJA31 z4JE}Fh`BW9T&4BkMK+oMsQ8hzZ@k41Ier14+y}@=^vgMZ7N9bJ!%umOi#a|9kmd^W zfv!?K$43Jydma5rZ*e}yM*u1@ecB0cF^=QM0@7YadA6uR*=@cql8?HHd3Ou@iYU>tmf{_zdqe@o|$v=(;Y^0edf?CZ_qi~ZQs(q6(Km$UCl zG$pw(ZjOM8KM4zF^x;Ry_nW`j;LU060BOvKS9PQxV?P}4#o_{=$LvmD&LL`x?zuQa z$4-(1=mfkcNVGa{M(fIH^LnuM^r%B)V$IvRznYD8Du2#@IhbtRRT5CHn=+@Q!<6xIWeI*!-x^A<^t0yic{5qOXeF7Wo~xetwFo{{m% z-wU~p<33F~dl%w5r#}U#?2}cX8SljSQNP(f&t2w8ypMpE`jw{^Of4YmGk$kuWEa*( zt|OO~??tmaGknf&CTpTIQ;O7F`!XK9%Xous8Q)JjWa=qSAlScv^A zwb!J&dH*TjDZ-rlx973%pnjP~gZW^C{i!YXso2wxu*bf&8qRpCXOh3mw=wvxS*b7Vq%cC&@dK2TT>0C*#mPvg`DqQ5{{(4eeKz`WeQqP0 zbd;w^)s$z;#%RDJJhQ}}+9}-F@eSAx)r)WLEe3EN zol?mMl3;*%bB1UZz#v!*`N-D(%!k8MX6#74tF5JNVV*I!-cP=^xqKQ_xWi zTr5MZ&)C0qlxgw34H<`b^#D`VLfz5@ePI)QU>m(*Bf+qhUO3C>iFfTavQJf>Pu$%e4^>PTmmcGj@(aG|4R zd`*5_k9bLl7gE%8Zn7Hj4)W9oJESe&TZ^jC_BXPA7UX2?TZO$C{5OqnvYwSa0gm#8 zI`iI&^1&AQS9p4}dN0toQt(Vg{fhAt)%W!(=P%n~ZoS6q!w^$Y9CZP8UT3LW?+rj3`OqcoN0Cv&Kb1LP^+ljbCQi*J&QI8&H|DGOLdkyAkF5CR_e~{wE(2~EMn~}<7Y`!S?pFuj$BnJjJsDnm3FO z?(kahbH)9uR-C6RAn6@rV9G9HeQS%p(f7L0mPz*;!-dQJ#kcu@*YUdcyzYLS85EDk z`wh1lEq^v(GV;11a$Vfv2R+H8lA)ti_95A&`8V$dB_M9OPjlGWF%?!3N$JC@Bs&~nn#niXJM~SI_ zKsvjYb`X`*T=C_!OReZkDH>-=%vMjzGB`;WWvG>MWaub;&GAP$tSt7fY`&`EyhW-@ zwwVE_#MlY3c+Q7B$rFw=+0{OoH=Xmad#qbO6tqP?N2XPFN0WWqjKu|U&%NX`&$JoX z|MRxq2UO+=;Wu;q5X#(&x7l+8ud}gM6Bdo~h65M(YuU9QzEzRC^ZKUoVVbtkiOIADiKdgYh~yx)s-P) zctENbK0z5jeDjCO@O<1}rg4;P0W0ovl>N=$pF6SdQ8;6rB>o4+5P!8~BlE4}c?^`<0g^j8)1Ur6Re^QMv+{ z%Fp?8AOrc<0=bOhRr5J7ou8ad`TMcA{7&9Q-ky-h>>y{9w}`s39qb2G>_jz;MS)tnrx~*Ajy^1ootNa4y{ByslErG@}6zc$L{5K0NFe9<~!r`tbo>N zSI*1#Y$N&khO%y_f7fVzFX)ciu|t}keJEua-3&GW)!_iNO?S1!3lN8L$`~a0WDGPgivapr_*)C6U8Hr7~%E>c54 zYCC%ux3{L=Vk_XN|E_>+t)#P9XNl?(zAhlOP0tq^a9mA5YLn#f<~TdR@^deo3ET{2 zu>;)^aYh+C6L6QTkfyURwG0vK$q;M!3Ssp|>}SZfseOCksr^U5D|$(2H1>f$dBeQFHnD@HMXk z@QN(Ip&rTd10dNn=^~%w&H&PUAzfVKxRZd2E#-U5e#2D%Jw+B*=>n%a0!V#O&K9%N z__%n%{*If^7Ef{d-GHQb>R(zt^e;)_=^_QmKHp6uo+Rrwz;eBLk__y5*IwXBPg`Z^ zCZ)>IRoW~=t+YvoPSOUz-dsoPH!-<_V_se7+<;ef^fBnE-Nk^^F6n4J$0YzNI$FhX zZviSg%5i2oQYR|?ag&yEx|x8oee*NT)b&i3a3|;}$$X~yHm9EmsMukG7U!??6`smH z8+VC#lB}ZvX*}s1a~#rSmt$n8l}5?XNfKq~A`J&5z3b~Lx^$MptzImt|T zHvUdhYvASeUxu`YF~>ReR?u0LIZuAJEJ%aBj6KfMs$q|SGu8z)aF-6>E`%Rd+RYuq z>>?w{vxNLB_{h2n2EMQv^LME&+{WbcJ5=~iduh>BCFZorEbfGu6S2ftE_2~coQc-v zXT?o~ht+J@H=J^8Fy>Lpc;XxZIxqWxwKaPQvkTu*OqR?Uj4oqGCwX6!x0scuX>k7( z=LP9Ls`K;>qd!rf^mqkOnJ+nN(3H31EPt!y7Us+?PJ0$mS=-W7q+52+{~GYLrhO|z z7wI&hE9Ouk>@=48gZS4Q{h>Ij&__s_PB`4{^lm6TtZ6D6D$naOFY#EoxsMdfodO?u z98t#FB7f#2Wy|e2NxNm}DD48wNE#!@7)=J5Z4h@khL$eqhwpb3JgR+XTRJeVJHU3NM=v zsOViKm$AEn^b9T;WyF*G)oi3mw{d{fW>jzUekR+U?Q0A9zIJK2Vq4~Y?d+$_R}mk! zhhfjUVmQCFCrqv>$dk-N0TugJp^V~z3BZy5hY-a6cCehs{T~_P{tsYf`xtp1y>=dI zzWYji;<0yGs1_dHblKug{R{uoOH3TZ?4T#gaW^&#v4kma6vJ)3i+8B8FU6g(EIWLw zi2injpz3ys=D9M5%Z>{vz8K3_&yHBTI_#@kgKs$Tz_aWE*qIU!LnrV9=5MJLPG_<9 zRJngS84f5{&ZO;l*`Nw_e5bKGp}da9qE7HsRu%*t^)-14@)mmoUyJ$o6P&;VeBtIkS1Tw`d>r2|iAmn28p4KH~wvI{s`7e14rR@xv#M`=CB zujNp=C#IZvDSJTTm2k~V+z6f1`B%lim!Qn0u+d&3@l@hs{V#0Zy$>ACyV-z>A4#~% z$`5AHK1Ni#Z1aMYK&fQrslavAf_df-Xd4l>kA zwPa}aJ+x1=e{KGmeUBFO@sJJQQN=q6>`WT^tl+D#$4(Ve27@*XvMY3tm&3+1^p0&^ zJlk``dZxv?=7jal8Sx3;vpsGt$0y2j@LU%jpJ?1m$X`5J&TPTh%S%+!`cq!wUEt{( z=A?(zo;=RX^%8#ro^(ci%E~AX@ zDo~tXh`a2LI1f_Z&Hm^(Yvbxk27du08ap~OQaQ5stML4W+AYL8IiC1CNF;ADHshA!p1GEVZ}$)V?1>v@@74a_;duL`^F zI;N1HJ)ZVt^9}o-Qu;piQ}hLYKTOtt{t@Uho#vU7w3zcr0FLBNM4tLO1yGr1`G;wq zIY|qEqrOj;p^FqHLnmpX3~`1JsN8|Kw>8H|EKVN*8yXH<8U~vh3fmfj=f)v;Zp_|q z9f!J>v65=Pmlz6Lr2hN1Gp}K<&q<3ls|{PThJsgRYgT9Qvs`+L1 z%HQ1HtLr;k!32XM4DUw;hN?HKBQ|s=a;+GyrwkTfLwrci+cHG#%<=gg{?nSKmoWdA{qve8G{X5GcqwaIP6qR#SAZis%>h)_ zG(9gn&&v)2D*iQL2h}sLX}Ks<*0lXdQ(v+GX)I@b!rGvH_E*4BJ39asUTOUNg61Ks z>nv?Yxw0PGaXtF}=~liT#%G)7Cas63?ab@pQ>=N}@YS>)J_R3TJxoi-yyNTPCg7Rh zagshl`hQV&?r~a=`TxJ~nGREgy6=0=Q!~XXYaOFr<@wz_O;eEZY_w~Nc zC-F2>eyKCWbHzfHQO*uKe-)r;egcZGe;NB&I34`CwoqaI;ljM>!b}F+UrS21htm{> zu#&lWQd?N%)(py+%Mfpu;Fjmw!YFo1&qdfNEvJH#uMbmkKjq)K4F~-=rs4t7$_xYS zGxficzVW7FyTQv2a1nyPEFF-z|^e{$@45_;1} z|7nA(@2l_j`VkM~jz-1rEiZfVFFu=YPnMmsIg%ac1x>uMa0_nAgUw*-9s$2U;FsrL zlV|=a|CM9cY0RET?y`aAJ?>oEl#HH1xzmMDZtuw)YfjjxIN|R-(95d&ckt)z-vX8A z3Mc=cJNwr_GdGF6%4YWrK63W2f|{H1{@-=>OF%!bS47-zI{Rn9=KXoM^$h;*?4JPr z-mD_*x6X>xz(-Tsx2`=UzeH2KF9dDfn;$-kS$nA-HkcDu8{`b1LC*gf%nJWtko$i@ z<@rZD3j*Qre_Hv;-0z(nvo55(-te3hbnxR~Sr$mw_i!ZnXzX{H<-` zwA+LUroU8I-ZPkjdn6+=z|(nty7HL)|JaMS0Q6<0;)b5V1ZO`I6dyLvvchrB{v^=n zamn>PgY%sIaiH?j`#;;+7lS_SQQ|(`*&hKm&sSd8GdR)N_Xm~tP2?@{Hx>Td%Id&I z&F$xfhv2Sx%YzJNg$EeS3HLXc9qwl^Gwf?H5&jDFX^&3nY3>2FVPj!0-2B|-gja07 z>Yc*>W$rSEu#)%q{~&KShX1+#&tc!~Lpz@q#>G!N=X|!`*0TRoxemIl2cC?7^?%mm z?&lsBePi7YzTNi0#_Ruo;bE=iVZ&|h^Y9sQwA-ip+Qz5;(jG3|m0#^+)*U5h$)T_N zPwi8s!{7h1N9mvNqq^>GP_!xsC;L+k6IEwM=6r{nDbH?yT;r;Jn%C$4>%vXNPW^}% z`S*L2{)Ace_;Ut18)q;URyq5J9H#DRfM>J5yE8qFIgSqWi#yUk=DpA0 z&VCT6x`Z$_^>sG>vrPQF|BIVsaJWIv{~OE<4-u}m>(P>}c&z)a2^-q{_#-9B@V0-zbc~Rwu!br~Am#cq;9p%Dqt0WC6Z!*}o5hdI7FdaYT zggp-Q>8u{9_8}HF5l%YOXfV0&ZA~S6Z`p@i#CI%uA~W)Dw|q)orOR!bR(3jc_vC!Q zVw*n=(3One1ielbzhV6<+^XktOq=MQM%o56;g`piNIscq?YDL*HyLE1YGJHXM|!YG1Z;t00cq*h#Ke zgU#(F_PtNHa#vWnUkWNM>K|N=S#%;VCgs0qnU#O_Q07$FliK?-8~!R6el+OmM_woh zWG@=}iZ93>Evz7{`ovm;xe#|R3%QM5-#0 zp*!M#_|wU@GIhRT{8P4#n+zSbw+Z~WEPrke{V&$vMEr@~@+WOOnA+~abG&t5Kz{3v z>=`V4(&opWiU)aYxiv)|gL?*Du%El$)nx zu&?Jl&Df_}+Hb(V5c`F#?7wsNtDbJ@|7+|^+2_;yuPyBxu#Z4zYAbv7O+Uqrw))wb zt=vAqezUhTcYsPK?0o9mxam%>57Op7p!+=pJj%!=a_gYobrgS_EoP;-&f=BwHV=O9}h}?XYEb-8DV+RoY*ngONRS`l20Rjpq<=zBEO}FWRK?E z`5ik?wezY=#^eM|2U>H+!OZs@8rd;?54#ui-0NN2zphiw{)%&Oq^V(?`hevlui!2= z(Q7DReYzs4gS}kb8KAFED|*4-<xbKFnznF-4sJ_<{|vtG2L(S@zK+V_v5(4g$%NAljJ`$WpT4Y7{Ot{@EQrpz5&BP;SYB*=x#7XiUoPn9nChamuM@4me%Nb{NplTZm>=YR z)`+7~O8zuaj%T)_neS+J1l2$60xn^WmGm?fI=_X4UD_(#9xmLEHz)g*Wy~dc`kips z9EtX4ZNv}nUkq5-Ohfem{T=Kj->*R5PpjBoVCr|(5u31Ae{79G_V61_g!KmF;lB;W z!p{xr4wts?Md_Y2t;@c9Gy1U0HIhj9f6%BxkBVqNwa<5uOW&*5OGlI^)msVz=*%s2 z9 zDxg2ho?qwp51{C&U-=Mb)t72d)aO-L@o+cj>+gBS4|jNg3tfL&GF6yAI{&wT(r?+{ zhFS5Km)ZEEKNJKCE4tT%sqKB)`T}zXU;L@Rt-H`F@uRf(b;VoxSG|1|I6(arw}adLHya#m7rQYf9r>pJU!FUrU7G7kq?U^0zUl>h(w(h5<-YYf1g}qql^zJg~b1|*C z7piWZ%{%e_Tj%!#gDuy?hqV*WLmjO=2I613F_HRJ^6AgN|h zX*RAx=iUXh@$mjHX6ci!J3F?MX3>h{Pif@slJ7qlJJihC)}H42g{ukz(Ucs1xGAag zbqxi<>QbLh%|Fop$6dPqAMis*r>@@S#}@2FqXG1?EHZBDb94U3xqkwBnSPF0a_V5x z!TBHa-}1hkcW**oq(T0+8uxhk9@tuk{2ococZ!bWTK2hkv;M`~3)qWRvFpE94X0jk zeoH=6dFAdf(RRAf@Tm>2aYilnmha5)Nz9r*VQ&HV`7(y*U;HgH*ph$SzW;oCX3yCu zjcH+xqxBg02A|SV^pTbE0{)ebO3?Ed#qECnJ#V*SPDCS%6|TOdAehg;%+U`Eg1ekQ z{nr*31aq8Q*-BeiDXgbkhn?wjk@kude@drx;d<=E%Y~qCBg@{kd`@w0=Yzg|s6E>1 zTg7_?!6fH?7U<_TK7HGU)jkT*6zx+$-(E%yZQW;)7oLZ`Z!b^8d{la5fcR2a(Nx&M zpxQA%#wmHn)_H2zv`@Z|tM^WDwEW#8Bly=`|6$;0&g`1`f6PXn18f?K{vmnUyB&|f zt(5m*j)0!-@FcxWg>Jl1ylUrty1$b&G?gE3%hHk9iDm)exX&H^$q92Ys}9dLm=$Ik z%naiO6JZa7u~2a-oqHJMY>dI&pKU*-f2sF}YFz8jI z%KmQiO8)s@&%JG<#20I0=plC?5QqHn?wy&JD_TbT>Gpf2ljiU6r#$)y^mRq~Z>-q; z=ULE}pX~5?%xaq#8_W!!F&Gb@HW&;4VzA{rq0S@zX%_vIU)U$*b$!u)vYX!^cmjHh z23g&hkY#bvz5{DAvaNZAb6d3UAT!3S-P@+2Zb<=qtJB__g*@+vhU7UDRDEyvOhwr< zmG;Cu?35Q3eqNt{{b?(pR}*)Wc{j7nC<*ULDPR9!~A)j9Y0%IiEvNnXUj}4liY9{ zW}_dA#H+?XnPEr#MdEU%3sM}as1oZ)BiV^6MhQ%ePSy<%x*pdY457h_+Zz2#g@;E#8(o&ytn01WAvdCS(Z$d}1sM@U{@aBqz1wkG5s;BxQ7v;g0S?t@x-==DtpPRv) z)5}N7u5w}4Xtf2Okw;DJZ{&WO9b3nw_p2Yu{2Jjj&sKrE`rIA)_JU^ZPdg7QojtTE z?VsuFOHP?cJvx;k|9Y*zz5}y&w>sA-^0u2>#*R7lS^}im(@7uQ|6TL0@*B z#;mdLM)NjOB7A~>@%gyHmVBzu<=1&?f3o>)-qfL=sCj;^IlMzYtKS&mUw6BgZ@2#5 z(|a|%i=*`*Gj>S-<@;71bUZu&N*?0}?bCeTq2dPR6Z`ORQ(9PacvgO*#$Nfy{huye z_4Ua-y~)wM%3v&!Ypji`JOl%l+zxe0WF;uS}sS9;&Y?2qt3Z<=?=+ zbml_rly|3qwhSb~(=jW|@JF+o_fS?%%^F?l_c#ANyTzV3zh^QrO*B~xB)r`_slC{V z@Ff1#Mjh$smVa(_qizc0f9w?h0ia~2cuTNXerqhNb@-!j^L5I8m~}>}uMqcN8C2bp zTo?3v=-QUgGu7M&Fav%@zGW`?gB zY^ksQ-qp5wklZsq?_$N3X6USHv}MxE`Bi8teTzV)Z`G$Q-Jf^vRiNkZVa$?4$vB%{ z^{=Eqf5zVH&jXmHi}MY(%pcVOKgaKxWtQJRn6S1zorhU`-Uxbq$i&~cRjK^ixyRd0 zxI}m@X!sms`Mk-|m;@?cX02=;HXcqlVY$P{V9Pr2LiB1^d`rHU6GriUc&_5JdVDc< zw!GVPjN|`{w1^pB&@PP3p`KKj#pfi$oQof&b!e-wqn!QGpqD|B31`!N681`$^y&!A zlK()1j9(45Opo%R^}Jo#nFWEuD*is8*Vm%63WEOpTl%rEcQZYE_C~ZK9qe7Y>C9c9 zgRJ~rz^QSh&S{B$xw~K6&-d+4xR(AI`xV=Ja7*xC+PmeQxJTiC*K_Hd)p6@88HAOb zr!q&Vvem)xuRP-Ipc$HPw{1w_Gq%nwJGCI#z+3BM-?cij2|tp_zd^}fa}M*mSU1sa zye2!yWQ-}<@8;sV?_^s~d_@@55k6kk2MyTyKJY)~&e*0QqsKv_rFu4gS5A^X19obIctt)PW0J7=Lahcjd=JbxSF+Z#nHe#q3WbpvGaNQ1ZLXq_oIAj z6GGZ^@%$L}t=G#$BNAF!l^kCX5Z35%5$2_DSh*|`f9Csu{&idi5t(@>X+g55nv1tB|aB468*#fmGHz_{aw5z}v z`M0xIWRT)nz`x?JD=7%3WA#FVz-+7t3+4V^s;-`L{Doi_RMTNJRd*uI~r`S zjnsN&N6y(+MS6YI{(MwM_;EDyROD4Vm%aEH=}sa%TlCPoV$iogaoogj6jVN)f}7PP z-tfizJa>JHj=~@B!XE@GUDESL_>`V%Kha?9^)}Cp8zVI{y6P>4mUmLATzfZ#Y3*J} z9=EL%b;es|Pdc9-_9G7E$-V{?VPDY5d!XfC?Oy?Q)_*MA&H3-*{CnNgnZRhfI&a%L z)xmo>+I<`MZoV6`?l9$JWX=J&N!NXUvBcQN!k=#Bu6y#fob>Ciopt<+-)#nC;n(i} zONX8x%AVQZ>gzdhiR6`*5i!Ue=uNHbSk$+3QK&Mp+$soam%QmK3IM8K6A`%F|vQA_o`qE=$9q#Z6_M zB25>h6)zcF99jPsgWC0(cbT!(ocu6H~bw**;mAxVvmlUHL zy$*^@t^)_}ADK+OJ8CfhCHxnD+TFBG3O_i5Jzcm}L?VY3e$xF4<)!TX`0#1sEhR4^ z5#H({P30eV-%Eb{_^Sm1Cm2U9vm8zJbWE;cQ9;imTS8ql{N(=nU$W~kn`>%2E(r!=b#y9#sbe7OW(v`44) zy#uNJ)oG4y1OSstRrzy-zn|lvCzHq+R#C9bN?6i=tfgHb+Fo&QT&(lFaDzV z8Np>&`^nxJ3OkEL{4~fi~&K!!D?NIEey7LkBW1KwF3WAfc7p=oU?SCrI zv~dpLUo@8&CHqf>8!}D*sWRQ}Y3p}v%l^|*gi-%VaX0jd%z29V)pyz(d&#svxCzw! zmd>Lqtp(04&!GAW$vrUI_ac36S$`+b*43YrAM_@ikqdL4($j4Im1o-D6-ii`m2IxIBW*r5Y|IZnRh;DGGEh3Tfxdhx`Kh?8aUU|s=GD8--x5%|W7o(c ztdT{Zkl%YZAgiIw&ktpNj5xL4BbxQ}Bh+8ieL{JRSynQypHCht%)lS=gKK*q$9kAw z3-fPrC&HHrt9uH{Z$&{+O_B!#lxEOeDFc@c6R={vK_h;!181J zpO&YG@MHR~+w9xYCq-=fXJPOAyk+0y2Xpz~Kp$Z|?}?T2mYB*@Id+ogjo?)5Wxm7M zG5$9g52t~CEoMTO8tb`FI-nc`E1jPocf+IOjt0`3l0fUr*V$ zhv$85=K?Qx@u}ZE0kiUOB&a-8`H=lMXMYmt>#I{SOZF9CijJ+X&cV*tSI1+P{V;y+kU`q@#2A(?l^YkNfRy|xc~ZI125@TeD{eHE*bdi zeIf(tC#{d}+&OB&#J&Sn@6gr`63yCymdBERi^q7_75d_D!*nm>cz73fO4mm0{N1Eo znzEYLU-zv`^yerxUR`f_?C{ykxKF4Nnf-O!Ca(2+gSmA#O6cjQfZpQX1!lk;uE zH)l1kg=HT|E~oKuC1KT<&Y_&zb<(WxHS8plCqcg#Qf2s6XTJ!fvljY(ja}c) zad$%Hgnzd2%)GrSv;Zo=`vLlPAj=v$Jmgl-j_oZpSqZ>X%w~=C7k4 zOdS&sFC(n&{qsF8|y3m%N8#=DpSd=sq$}tSf3!haz+G zS-hQ$Kk?=HDW@*Yh9~vE6`$yckNyTZ{{#BGSW%zM3tK1Z{LilI#6rr%uMM5Fu;Hhj zS=#s9wr!_9sz?SA#k`9amJ$a~^n^=mEpS)NvV zbm`3Uqh{QgUNeI}lfsl{+A>!5Qhu=cI;$UFfL=ew|0}EcUi8{U^raYsWw^TxM(oHk z;~m|LF5cG?Zo?UAW?t$m%u2t;fPW`_imPIY)x*zm(;oZM9=2^;!N2-kZwS%1*M#KZ zGJ|Rd>{`sO)?o(MMkZG>rm=U4QIDiY_v=U9+^=Z)16@14`~H5B`X2^IyM9wo`I}jMb;NlH;cdJ`2Uzs zW$JEt^)f5@Yku%B{}Z6AeffpmY&!44PGjGzTp#Ddu2vp@g9i1BEssyhj=jV972WGo z=thm3UB{Y@y?99Fa~isl+V7OipXr<*XdHHQN*onWD2`;G@*2W5_XU~DfsW}5mZsV> zuQ%D*pNoA4Wg&Wy=1Vd{$tRy zr^l~N8Q;v$50<3-NAJxK7W3a8??w0J2T!{A?gKsV)r6Tj)s9pC zvv);*ZhmmD3qJ#FrhgCgue9{C+kP>2R6F%B zv|6`W4-wwz(Ovmwf953q+m_X2pYX6RtUwd|c4LlxzKk=Uhrk0}|_rJ)Dc@yEj{I@PYdtoPi*u!8V+}&W?eLyB%?Tzo< zn7rYp{6Jxqmf`(U#`)MQEeGP}>pDNqU)$%EN&X$;jN;Os{RWoyoP)o@qT*hvgV*+1 zda2?S&9a%cKTtX`)12)t1HZpU`|@6%w2`~|c1&mPdsc*TfW6;VVIm({dDWHY2VY(j znLC5=%T>25cp$o0Y0pSuSxg3Qs8jIy55$h8ke z(EGEAUu#6l>(enSpB`~^QsoF(wW<#=Xou;M!ed! zY|X3cKA$g%^Ipeu>o_Zjll2GgG3dmYp)+HL48{=2b(0OG`$uG=ciz<(v}>>(!<&72 zr&zh)$iK>#WKgx-=2_X*`GNL{j{VBkF;nm(e$NMe8I}LlHCd)DD!R(j(wgN&N5Ae$ z*=2_pxv-~#8e=Kk_?ziJGA@_7_N>g&%QNge9CuFcSn+4qe|#*hW{bINDjo)e-Pk9> z-qnt#PdSSJ4g1>g(JS(U)#Eg7*W61yJi*0xC@7iB{&38StAY7p$+(37kJuwDyW%>V zW|_x6Wz*9zDL)v>`i%B;Dy-7p3sheDF{1KOYoNLx(yoJMh57gq{aoR`jCX|WtIjm` zyy0gs9`-O83-<#3TGHmThm()TGxp=HJ-@C*U)`6{HRK~>%`hWAq^8q@Lu{Kh3G7fo04al`n01hw(A!R?D#HF7d6IX2Y!# z(vS6hwSP}T7t??KZOJX^ox`T|POOVsz4Udm#(vK+j#s+?9aBy}H<$=NHJBNG3@WYD zpRsv0{wnmxt?}0$n>l*8yN7ndgI0HR|DM*uw{o}E#($;PG>z+67t7?=ZA~Ip1%= zpYr`CA^AR2*pvJR%X)*n-Mor1lF!$d$k#S{03TyrxKc;wd?9p43sdwWkY3D^USy!x zUC{5Y)Kj}rPjL_a^lpq()8}kPFSeo=ThNP5t={5&o;iaThZYY~x+}-IIgMHN9@;aA zOLh9`1{2|_1~bEx4f2jS_*sX@;l0vx*NyEM8I{Mp&9+M-HMMoNPCNNSJO0clLzmor zKBb3bj?UQA)kWOrGhwzL%cj-n9K6P0he3A}_0rb=>KuGlcrgDzQa6dmhLiK%{XVLT zq&wN+ufz}fk`SUV$I%~cH0x(-hivZ5H_-M*Ru)?dbXRzBQGVC#k9s_PPAC+Gja_*eZ~&wBylHS&O^TX#HkALicOaZz*M z+*bUF{%X+Am3@U-b@>`lVXN*-)|pFhv2|w2v5ar2GxhfKT1Vr3Q0nMXSr-8u;!I}u$w z0i7GcJlgOYbkMB7yi8bArhZSEa`k7lSaQk;Uz!?;e~JEyZrR}cKz0A~*rn>f+@eS2 z2TwysGI{{?ee#lH@`K0uS3kj*pZSDWA4+Q{1{rfp2Jc|6d%?C|oDQFD?*>yp%ATQB z`;{I-$H;x^kv31~ns_wlm>J%QS-eaGeLG${+vZQv5&6L_&i!)Gk0GmW&olN)Pst$Z zmG&^Q{|`UDKQerHa*n4e$IkIA>gv|ZuJ+}EIUe`+T`(X&xQy^h|D~YjMpZsE&w3&M zMy`j8|E#c#fAM?*==YC)av1ISqgMCr`iRORbj=?J_fVHK0@ZBiiFHh^)mKZVSz#B z>I`OvIR@il7TEg!uB{gjWqrl&9f=kWsY&ai_AetWj`ZTq@?@JYUdnH9<@7hor%2P% zhpdeDGIW!5e%tX^%ej)yj-QSOsTV-eFX<<`_8qrvQ*8fEdAJs{>esIgYHc7n_w~h; zNPNKV(qXN=L@9I0y)V99S3l9r|EJJVe3gIi(>zyFwy*LaGDp10f2|v9HT+8Ub}#!! zgzxXqzh3S1x=()aF80!)C7>M}#>00oS5db<%Up`=MPr4*c(~YLEPTezuzD?fOEaK0Q@ z^RK*^hn>=TBk27`jhk&h?r`o?U08*=7PF1l&T(8xoUL_h(Zsxct9S>(Z9+dVn>@RYB$lk~UJMmZQ{EtZWpJUymkAVy4 z>(XJnkXbZ4KRDUZIy{9|G%HDqutpaBLBm(Vx(#;W`hs4rb+`>O{*(3iuZUaWig2sF z$(BE@BOWN3wo?Y=cjXwXs}1x}~Y`;8>wy^!SW^=24m+F7%_clW_9yU4JKN{qX4N&RJ z?q+4E`u#iXw3eXyRR3%B&-|r$)Bl(J7rXh);A~f)Whi`B_;1{#+i!q=d|1|rb%&K& z`#?T7c==?9E1ln$Ks%nz317uL&(#~%(4-z|T6ldj%pbWB(ug=g#}~$IgdWI!oY1?a#B&(SJ@y`>*vX<;#=Ui~svT^_S%5$aI@F`$j-+ z_$Y2#&zfscZK8c!egXf**V(u|y$7%py;-2?ubDPf{&T{6OnBlom>rfIWc}YDXZQ`q z!|M!6e_P(~sdi`k<-89~+cR0ZG4y|Xf8`oScPgm#7466iuE2aKcgscG{c^R#ZN5fv zn}D0rFcMUs<1BDSTIM?Dm`5r6;m2FQ)m!qAZ6Z9+`9BWy{g0B(xRF;wuJU=A8J^+% z9R-T6^k*<;(Tq0b1*_bgsPu5Sw<#BiPM>?Nt{7C+7=fPvhee1<9((jAXPi?txL31|k&0`Hb z#>(s3AH+|`FmC8Gk6@5$S_rRJA@!jJ0X z?+nJnbp{jRT7zxp^0!|6+M-ogwKw0J?6WFAO1{YpzJ`YQco+12&$@5PC-PkLx?f;# z`w5xh+n8VFymmEf#+9r`WJF`LD_N6J87;iX%Ju8u~=&t8%aMM%L}vckBBBKR2hhnYkG89$`L3 z@zt%$3m$jroeO#$Dq-&1_pcwu-s|lg%wMF%*VU2UMU0tsUspf&PJyPp;fA-0bEz)R<%^1VY=cltS{yh2A{yyyFKEn$5DBq*FiM!mJ=W`|! zu66&!@7rF0|JM7qA81D(d_Pcf9ZwjQi;F6%o zlz?7$sy~w~8S^{0BS5b|M`KRz$Kwny|DrX(V9WmNf$-aU?pk~`e4H07JJZU2AmJ2$ z5vaDf(4CQq;zx83!ajosqcoqbxopLqfmv?3xM>dC_nH0Nwb7Fg^MZ%ZuyOQ)5AD1B zxx3N49K8&Nf0k+Q;b#s=vh7Y>lI@aQ{E{+*d*Sk{3QEGix|G(9S21 z2Z4p4|Njv;g)doQ;}FeW8Ikp4DcAC=x1oI8z4>2=yZD<8DsCHRR`{U8={;8JHpP1z z{|a}j!L0CRgPGwhgNd-hU_6{*Fc#hbnll9O((ld8=Dl4dW}jaUZBcSR>XtD>=?@N} zFF@aZS=99HrxL!sagTKD8r+n|vZYq{C-bi~oD2H??D7?v&135_=G4dIX7wr_o`pH# z_UzWxS{kL;^?Gp6r%TdppP7D~1wHLWuP13&yqFi9?))49`Z$ipe3&bvMXx9h z&i^pR?EvQ=%z##m+UM(%X5YY28#pE!R@LEFzygs)+4 z8fM#V&XBG@EdAaGl#lOWuX^HTuvdCy{o(2JvF9C8W6%9RVBh^MeXSY1z<%H20mqv9 z<8Q>R@rl}$m+&Xv9tBOmn|{IgU%PP34=arIn-xCo{5}Ax{_5-e)t{YSv%-gA{b6$- zTTd0Px3Vq^siz*ccZS?VzASKbDnXl0-tfSzHLKge1+1BlM{hHt3qD=YHNx`^<#+dv z+V{9i7FpfV9P=HH&Qwr&p!8pB=wye}3?{-UpxP*%LuzClLpr>6QL>)U{Hf%>V|v^7 zcF~DBW6_OC&}dyQeEX#QzRbiG4=)8pf6BwIe*UB7Re1}Yx$K#8Z&fG4^ZC~vj*Q|? z@AbMNvc9oHWR%~hHF5UMBfEBa>Pqd?qHi#&(#)IlemAmH-`oEe@vnN_&b`FLBMcu( zOLETYF!=X$yQV!dQZ%d7*K{;1pz%Frq*sxBW7gZ3iT0u8BiG_KyfFQ}Ufor$hHgy_ z8zt@r+{e^*SYOIMuo3Tee$R&=d`FZ#jEoYUkMUCkegta%x4pUFU5&@HOq$|h!eAnd z8O#j3gY$g7H(zpAA3qUhV9y#+xZI@At}9DE`yw~xP08KX?@w1G+vr8}=`*{wH8L?V znsY{GFQ4}Jt#~7|d0*d;W?eQG{y^9b+#Mx-`!D9rW{o5sev8@P*HAK-egkc@+A{SU zR^g_3)Axj|oBdPBeCpdmm0N?%+Zl|9Zy4kb53u!k*3Y4~)yXuoR;sd~y{VkpT7N0} zlg=E)j1H0YrR2v9?9?`D{c9}!Z^@+W&b&b5q9uxpx?mxwdRuE{oKfNoUHQnpkl*;- zBkyrP&-x+cb&K%7v*Bx8_`6$$SKcdcte&>)liqPfByMQ!F~scEEMboRKElK6;Y!07 z=uB!{(c7puq4xpyE&J-We*fU@TvG?%1`V|lw}VP!v@$QK!0g+qx?9zEiiOu3f4t%4 z{QG&g3*c+#vX*B{M5i*dPf+j9lU#kXbjiM_F_-X?dzI74+7-EhXlku%95|k_T`A)_ z%`cwDzs}vN-Wh{gc%nmJc8S~cPg>`(_B)G@_#3uv{jfqjq=hG&@OEDIc+ASjgTUtW zmdl^rFFDw`_XTbH91DMqS@P;J7_@?F*RF~O#-1Ig)*#2vDdS0NgqQCL-B>lQ; zlIbO^iNn+S{_^(st@t|K%7ncm&=YT)LCyInO&?7YUAu?tJM3jQZAxCSe3Rw-wxcYn zPpdY|`lW6%v~0L9T)1k&F@B|vV9meTUG-Qz{D}YF8!atQ<2@Iy^m&{24Ois_|G-Y| zh>3zVt&jM{*9uIH9oT>veh{KQj zQ{(by0HlwiUrt%OhqC7L`)Y-A^8=jIZc1H~tii3_a{goQ=5oGqg7~!MTzrbZ2z9E` zSpIl!Fc~|Q^9i8r);`dC{`iR#wv{fvoy%^Gebw6ZC=I4}4u?vl;1 z&R@U#TZWf??Rk40B-+%)@Bh*H>oUKkzay}hyiRa{F~ou|mV_G;v+`4W|tyl^+{?Z4XEys&fge@@r|vv~aOGCQ`l{QEN$HD|T#NB-RT3F+Ktgx$GJ z=Lfqp4(-8MBgR-G&R8SCSc7+nXXy=MEBobVBxNsIjbi;kI`%F!l%6GyFS$)QQ*QJf zoZDYPKMxl@i@6>CeLwqY%qq`+0T~l~&w~H6R(7=i*opQ+(3jDYQF*~LCJgU?fr_u; z3|nrWaQ^R2@n3lgeJQtxqrMk?soh;)iZ>(H-st*Lk9Dfq;NFQSA%BKYC#9a#vHT>$ zd5->#ps$%6bNR}Dor9T;dns?HD2>vaJakOwrq20oaXV)kGs8;!C(ktIgwy%g z`KDg!`Rgh;zio5?`jV56<4XL9e(?^SZ^{hE@bBez31-P{6lmK;JC}E%vp)q?nNc7d8roT039A+O^ zb&2IeeahX9-$b}=5@G0HH-UQV^>jyL6aPxb$>u*6uIE2>PRP##soW{tQ2c4UsDFh+ zRwkdnB3yg-+Gu~F_|iQR-zqL>NIsIoBKp_E-TGh25jNlJ6+g0D0eYQo?4KNe6nCP` zxHCl>e~h>&IsT}E-b%u0?q0h0E@q8G81EQez0B~M8U9UvC%XsUPp|2n8Jxp>&$KgKnpr3IbyYE8B+q`J^luBgRJiZ3 z9ePiFyc_p6evw`yT^op>dgi+t9=7`Rk^ZUs3XOenQ&01+x-K5>hgo!Epz?*f($du# zId|VcBWr(l+#Cyw@MraweW->GXLyC^ZHD=mPPRWM6G5j`pGE1@6|#58*KK9J@&dv# zmnVHor%p_s3ry`Jra|A7hXPw3wq0s@UjzDlAD*2olT~Zu=B(eMG~1TdoSZC^_KY9v zh=jH2Nrb;M{3pVXuv2-Sm$7#)ZP{neIB7^tU-C-wGyLUQ-CId`$@V2s`90I+ zcSA1y|7O~DoU{a*3R{w6!~Pw2{YUw?V-4|P{l1J}&ByF&kA&h<*ztS1xleRO|7BTu z!IRJ}&#+^RO=sA?Y_mVN$9<}^FUqvMR1-$&xE=IqtY9sJ_N{5@U4E>S8Q$mom4nhz z_Q#ue3s1N46vgQS%%Yz;E;46t>Ydrn|J9)H_msr)g5JOLG|hW_J#@A}G{wUN(C2kg z56hq0lWVY7dwj9MtnfmEnc+Bt@vsb(3@W!u9be>(@eoJi(u(XZ=d>5p>$j|N3g{k&5#+x}c;D0|I)9SIIj&t6y2+0JJw zu3^|It^+_HwivV0t#T~;gd4|vI4n05ODv42_hVybw+C*9o+Bc~;m3vv}(as&4dSg=j~gN38i7KkWax zgnpd%A|kI5TNBM|KT+nlTF;rK?mcWGoWk@ypm+1zzxsdpH@)Y>zbQY<_fNXDHwWYO zciyji&)2x~J7~7|Ht~m-SbF34OVU$Zjs1GhPaEHNi^c`|ujK!Kd58GSzBa!1b`jqa z7hm6f|2KM@_ObL{-UYo!q1UqAw{=3_y`j$=%NmbF_z2-FLCyB53qV2{Xz4HvG8hVU&mU8>ZzHRcs-7XlW>#% zo&`!DN};E?tG~}>ZYv&Mh`st2qYTEv3ml&2Fm<1d?wyb>6jGn1Vq4v_^8etwTr(a# z30mUeFi_=MX*}N0=lx$${A6VHo{SQ)c>}+` zwkuw)UTb;j=jiqTJuiDZS}{<(Ebq~hmwXqdBj|Z4`Z_nrG~r^Q?Azm|J)NxnGB?P; ze>ro}V0-cQU6G8p{DEY=Yj-B>x{o_Y<>RgXAU9Zgax&h_cMj71M)~);wcF2>9hI3*gp>X(X3a$PvC7U*6RiG!4XW&{1Mg+s!n<#F?q7ha z%d`&Gp!$QgM3rONi)O_#OYTinX?*Y#;kH`GKwEKsx zEt+r2Kk>BJ&v=ozTFcJR{~G$Po&JyGx$&!_=62f45IM96udt)wzuUo19w%Zd=lM z<6h%f_UQIL!1o0>|Lgpp0a`iaglA#a`tK-%S>Z^7y#H%37M@~Ia%#I@S!=vQk=6Fg zUtm5j%Df)&wlk(xdZia9LreTezOizvVC`iXc7AQB1Bs|yKvn=$zSnmKS@t#-x>6> zZ+cREXrH(}1C_w7D&5jN_s^ck+;C49cFTBwXOd{jLcWzS z5BvHewLyN}O82D0fAe~j_N(rue|K+iI(M5Q6EnY|aOvDlny&wL?^{alXMGzU$~lXA z5BK=^a`)VL!g1cu(CJh@k_{R0NWT4VSyv?KyeK;C4Y;RglFlQ9Yw4f)r+Ry)?-Tr& zF16;5WM)3h^#5g^Y0dA-Jl2}Ur{72Wrp&#qz32Hg;%aaIaq1aauk*hryy}@d4KnWn z8ohkb>WbEv?VSRNa3*fj>q|iCVW~S?RriOsey2IVrOvPF`*D~RSD8W9?G5U!?w0GI zXYGQ2dq;%5A6qU7^;+G%@^AZ*+DpEMa(kll z*B?~bR2dt9S^OSmFf%;Vp!)PJ`P~nG#ZSrH+~DCJw%q@xX= zoS@aril|SANaekfzecM-p+t{CM zKEI5;okz+FAIE%+%cHVeZ1}}4{6j9hXjWt1OdW0V`R3eU^0rKA2S*Uy=uaeE@1hP`B43aUKWdmJO&;~0J7DiUn(D;dmzcI-E zAFz3SaZGY9&F-UC+qUbw8gnQ=dlP==GTnL5g?6ti{gvJ5uk6koJog<;--EU7^f@ic z1#84A8@&j(ae&P6Fdy?K&hd*sXqvn!e#GWY^eX!Q*ePGOUX<*URa{9veC5WA=vIdF zvmQUbUr{|dH>hS0Llig8!#uTtIn2Vid#mxb5;L~Uz)vId)(n` z4y)78-6EQL8)j^V-48x|67#UU;U}7XFTpSO7Hp)vEavRL>0Ud_M`=zL)q`J*PfVe)zI;{}brjjT+4AgFOavpE>&x80!$%2=1WV zd|)x*sRL%6vqk0P2^aoeP?6D>yqz#jChz^Km6<#kVki7+43yQ4lmqB(;! zKfKkx<5(0}zKgK8d5|6MX~O1&-Gu1MZbEqOBBY+|Y}_@TK7~5uWa^TWs8dd)ZaINI zwcemepR?`4_WCK2Fq5#7%l8*r-H=R6Mu`W;@6K&4Zq4IJ)~S5Ex&?cMZ2%=xg>4wg z{LkxFpF~scpMX|wiSTpGqW!7Cc=)kF)tSjTw0Ge(wGS=2)u-kL3M+cAfu5ft?1%i_ z#`l49e;M@Sv0BXH*Y}y1KwE2`?Tryl9ZOup54LTf>bQEsEB>;Ra)XyJD_-dm>zCnX z=6?M9Ii=XiU)43PeLRu*D8?gyA&hvQ@50iqTfIFYH<Z>dqS=nO1F=&* z$2lT%H(23BC(omEgZ{WFuM3PHTONwAH}q)7_Q(ETE}rV6d^}mlV~HiGxu^IvZxR3S(ed9NKW}-SNw?24HqQK zQT3qQpab?>xzjD9pFN|v9(NzMVPI~c^NQQBQ`j}2pX)gTH}M}hJlEkUhn3&NMoR|D zk9CAA~&?A@=+Xb+5C36I9*t4){e{&N}+c=)7ps z;}MVVW3RTe4qQdsA@`#GR*r9Br+&8T-zAv0{?t}gmMhZWWyeto~ za2)ntZ=?N`?u#EHY<%a?G}bRW(Oz|?&&&BS=I~nYDOXt4Ib~quGU`J2rbzL}=u;o| z#JM}&LWgS~?@+UozOwRrLV6-t%i6rmwI9SruW^FR0kS}$P&sPn` z!j}!U&6j6McWS;UUCI~i=eCu9a-A`8q~xC#E^%~U0FC^6B<24X?7aN{i23K_KTq;c zSGnkj-gKf|P&PPwn>rS>{iw9?K@%ru0SqR>`Cw{ZRK0BTVrQS|An~;Jo21-}U!pv? zeUsnxXK98PmM!QptYao;r4&Wvz&!$JB=#;&j2>4%6`s=L1< zU+rBQ>CSU}bpU<)Tl=e=U=#J8+MpQrt5nC(_WZ~=T4R(wu&dfD(qD5cjkKM4%q?X^ zBO@CJN0z9)f6<(^q|K#1?~PlUi(}nb*Cx|;^nTjv$u{il_?Y`YFsps~v2)~bjWg3G zT0cJ+d)5vao9a%Q|M1T|*OH7##(u_-1zWUSr`+R7ieSd;~>C?TStq*d-`!S1-#)p0kIa(Wi!^-Rj`D8{E}&^C6ObH><6{CvXy(jBoX%c^rn<5zqY?&?DJu z!Fsn3a#N%DmYjJ18+(-*#s}|~zhL{s&*84K=fhms0~B^&#s|1>X8b3&W1QQ*a-*E_ zsO0YlcaE%oyobq$_q8VGb?^GGEI%7pTkPll`+|*+**DR|cjK4*Q{GRUFr;buD$IY0 z)NH4`T3++f%e=4;bbGnDGeFft>LV^a&W;^H4ja#iS&_=-5j0GWy$<&pdQy)rjwzQ8}^EFwwkx@d7yJY)#vN+I~6)=OEnf#|9u;F z5$^xkO228dnR~Kpp_{NTHG2a1N8c6J=m~X419P^D=UePV_cKtul}B@et&|n%@R!&r z@80p@ko$YiUvWfvlpB8T{JaL5b`ZXn%S@h#u6W!^9adz@q2~7D;n*Xstlq|7eMEC= z)_&o!*8UCbYd7!gFZ)m7-}b?C!#eCE#y&Uv3uZHBAU@Rvx^r>~cFJ@0jb+}7o#NMc zM0Ws7hrHh>ao<2$)11+E%HMSAnaybt%5Qc!AGg8jdFx8P-#JROL{s{tHJ)?RBa44T zeupzJCH>uGuV@swlwxasM0%E~kc z(Dp2F)eqTbj9B(gPB0NV%Ih;g^#jCj18aO~lWg5H*14Yun(-BKJq5G;Ref*iRR1F< zz^!TQK%0+ex-iFprf)$SOE9ZE`93au%^3uLCcZawf|&zs*r9_g9_!qqxGi*Uk zxV5*|>c=dqlLnahSVsgENBKI-Yuy_;!EdlrnlnM)XDGp5eXCzNw>?2yw`PVtFn>t? z8#-$(o#^X1L7wy50rYe#Udss*&i<#;Tt#sCFc%9;)>vA*VbCUMIhd`O15!j?4(J=fAd(mCI4cMQ-A?dT~zBWp8W$rbC^}9umFnfuRv=ukh0e zUq62jGrrT_1>`@slDommxf@LG7swsijWw8DJ674Va%=B=Q|djmY2k&A#yIdfXp6tT zH^-azKbD^r8$H~elUe&}yv07mO)JxCHZb2uXVU1*NU))g=G!wvqldJ4N6L+Qe30?O z`oHtr`ux$s*4smfD1p2g8-k3~F{i(6h<6T<1 zv`Wjyf7!GYIsSTqJ}vLcjB&@@L)F?FX%XlzLcU(X(}9 zY?=5k_yKj%)lOFuuUkEew(_-M zp{1ez!5Zx4ccnqvf3UPScON5v`K_zY2|mM4=E9}ffxnZZ1bfjG53hhK$KoN<#fGb> zQkjp3|8QX|uS}8u(AeljPX6Yc<rPqj_pDViOA$OihG<)ov$YwgkX>E%bymVG+rS+kB(nHBwpp(-n^iyJ*+ z{ZD@AKVBvzeU}R98%z`uW<1#5_+I-xQs3KDo2>m*Wtx9tf2j6`nsR+nJeV+ZNX?<$ zkT31I?1~3azTN(2o$GwF+NI~$(VDgN>(5i%^grzxvRK$nyix{+8D8vO2!BRE<+oW6 zexDPZIHq-bVdv8d(f{KKUy6K0M|nRKEYsTut6IK&F{2F)o3?#ixIT_fk&yKIwWk8Y zwSV3&c|VrQkKU5so3KVc=aJ7&F69R>r;~CY=N2~JF5QfUal$jVZ0bGR zr{(-FcA5v?cD~KKCNOpFNb5$bBihb+Ss6($eh^VEa5Uw=dX}Z7`r>2k zrK@j%GvUyNB}Pf2hBgnmA%%E$Hj-<)9zkt5}K1F#!JuzQy=G@*Q|s;q)*Ua!&Xn)D$-27?d(jlnr-H5P?&>RT-F==5yXe@Y>?4^i>+aiT zx$@xZ?lTO%mUZ``&{Mik!p+y+$6;38c9@VnIaG+BgTdDMpz_hOzlr?m8~8eHeAi@s z6J>qUm;K);|7Nv!*0ycg--mc5r{PB@%YM}!Ez5qt8Ewn{+)HfPND#ht+3%(_QTDf= zr?fFn2LFG{{!YTAmi>y0Y7+(-*hx3kGgS|mdgGo*h}A*gTGYvUp=q=vD*gblvB?voi!sn$m(GG3|r1qT>Yr5%jpH|l-`Fy>8p5a7$g5GEB2j)r%kw6SY=S_1Lwzy6uyc(@Dn^-r<%0bRdFZqz?hT|8GizgL3o>3-X`!KT0e z)a=0bA?wc02_`E%GCCLZ^+gHxtCsosMahY?!_MDnpkyf-o`Ko-?HW#(T;t(+*p=RC z?>(zK!`2A_c5+J{4<3tL+muhv|Ib%=x5s*#%x;gh((CtFi|5vRtS@atFS-BwNc=1Q zqd@6E#cAS;w}bh&X^Dk}&X2DLa+L4sst2OXp(NkLNF6`!@cd;m&DQy9l8?lRUg z*EqMgK|i@-`Z$-z<3W1V`mG+CjQ=J4DE`Mm_3K2dVMtE!oUw1IhYLsB z`hHjEQIvKsmy*Fb!K2U+A9sT4E6;OssXitrc*wck3VI%ku($P1W_U05;_GHmJQbgt z9q7G!ndNVFpU9jw=#F%Awxe~mqqV7Xag*p&^8aJH%-kc4`Csf)DR(@S93|Oih1X;M zQHp&X>z~@oJQe#h(Z%`RzgZV$?0~)29mGe&5#l#HyaYS%ufo_R!i%s|+D`>FKX3dG zvi`NUaz6H2t2h~yTZwVw{SRZG86IyiD;#Dp5e_vN3roP%HqM_j@%`NP+v8;U7M*!& zvxu`Xl5C5M-|u1i;gxQTvSR;aTdXpzGSZ*0c6^cuzZ5^zu?0fh^1xKSJU?yfEyg5c zUHlCP=LGqL^Lkg!zpqm=(Y4lLjhqh33HBt6%w?Drw-3`r`pFory*>FxHyNWTT*Co5 z!B4-n`SUgC=WENb-@<<>cW|gKk>3P%tLEAIUG>iQxL3J-@`cCQGFS8)=?rfNIhyZ- zY99`WMB-Y9(%TxMxA6B#I{#KY?r!M9W6|x-5ffkZ*Ewd-hUoeEyp@jbOOEblqu-g~ zyZmov4$$j#S-+fMx%2xps5Q;SAbP*p`>EL5>h~+yt9(5HYCnwRXzAPiX^$Cq%}ci3 zhyTalwl_~23FA(_W&7j=eDD$~&k^3I>tdI#1=uNFe^eYP=N@-e@294-jJ3~)2F!5*V)QrDg?jlO~Uc}Kx(>iqz|FW;~uJGfEtENeU0 z?bp6+nNAC*nRLd(Dd4Lc3I?Jl&q}|eq(ODrrPvo^_neb$gmN zERUM&(*Bo4w?^LE#Jr!@%SGor=;;12E9cBmdboJQc>`6BkHwrzSy8+d+p|rZcM5j; zukGRTe_M92@O+#9ecW8rF#IV04*-21t8S~pYfPv8PnqFSxTzlbHAq{<`fWVyYwTFV z1FO;^J=z;HwJdj>k5?Vx=Eoa;%nlS*aqkJ5vPC&ALq_VeD-O+Pji>BKqI%C&{Y-mL zL>KZU^~@@1Z_^Km)Y>znM?l-3Hyt3e8w>T9*^Pw`mU)QvFFCXx3-yD3+d9vVS0&#> zhUCQ?Kj%nJ@oTsp31)X3ZTp$yehh@e?)nvG8^5Q`g>}aWrb9R$rpuW(O~0r#$+T{E|0* ze6)yvKR$X?X6oVvJ$PSCW;e!KfZ3FPgUNA1a!u^#?>QCE;)p3&dHJCSQf4m#dlzo{UG_bBvf&D!8 z$<(5Y)vph2>V3H@lhC?O;VFxDua@>{r9GiNff2t>vpPGNj34oGE-3!Wuv?YRJ}%nM zhFMW_U+j3?>e)-8eJzdbi%{CM#=`!b-~01DTN`X1Y;(9BTnsyUeIo1HtG1M94l{d8GQYc?RTAiexbIsl30MuFMUW){ zX@1Yw%)Gfb0kogCpHF|E@27v<$9dmb&di)SbLPyMnKM9*@1GJE)Y-nZmhGS5(i{e~ zXWW82K-vEBF79BU)+o|p2Jx-76>iQ>Y`@UsJ`v}3Mp?Ns%%$%QG`P?;q!X(yg9%gq zTmy6cYy-3WI8b+k`bRQ1hFWxgF`!qGp;uqxMJx4-w}bnOv^PrFo_28VCX@f4QC6_u zUH!K0|E`3GJJ`FrMJ^24H>oq>YD39J`$li|Tk5AwKSa3tZ$rY#B*H%7d(Zi z-zC1@zi-v|65JOd|KICRx!|t0yuRc^_wM?uIf-|{qq?mG27Er1aPQ>{cw5QpPiouC zF5NPqk*m=EDZbBVpIvPZy&~Gg{67$;|Mf3hTCH&T9s&x##(+t0;w^sRB+ib3IibZ3 zbG*gUqYR$sauSa^91DQKd{RXC+A+@OGiw-~WqgqMLVR+WF+hLD83Vx`p|7vDyuaZ2 zoV|TKGY?gh*ZO$AwpnG{yNZ4MAG@+=0PPz^I(wn}nSGhZ`uMjJuKNblfx2VVKa#yM z#GS>UZkpqCW=r*(MHv`gf5pqPfmk<@!exE}rZM z+zH+Rz}{hR=>pQ2vR%3%E?o?0&%yR~w&gzbO|CzXaNTd|1zbwstO>_A*6&K~8@0ps z4IFQHD^LEmX? z(aEEwIf>$2D^t^QENq$;uC2+k-xtSS7<%G{?q2O{u0BrzgL$+5*TEbZ^Pe+ykgQ7X z6F)&cRA&8SIlMz+=ec@QH_gl4;oTnaa8G!-7d)K_jbfZH@3`l_N<(+gv~%tiZF%z7 zlogz(dW3H~Uxv-ycvGGaUFIMU*mpHN!n~_7cfZndzFG4|6S6!9{?wTyW(oFpx`yzs*i;yIS)XGNPNMXSqvv zG0?~mc;3#FdK(hiLAYc{sexJkw}HB++{*pua`9`Mc3FPClr(BnRg1lQ|8EzWqwXOeJt1p!;wLDb5C?`>n7VwVl zn7i-HaBXP^`#mV)!n$+DAls`g0^Yfhpk(|H