diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index d2ec3f52..f7cddc21 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -32,6 +32,7 @@ jobs: - name: Lint podspec using local source run: | pod lib lint ${{ matrix.podspec }} --verbose \ + --sources=https://github.com/firebase/SpecsDev.git,https://cdn.cocoapods.org/ \ ${{ matrix.includePodspecFlag }} ${{ matrix.flag }} spm-build-test: diff --git a/GoogleSignIn.podspec b/GoogleSignIn.podspec index c4ac124c..8dc255a9 100644 --- a/GoogleSignIn.podspec +++ b/GoogleSignIn.podspec @@ -33,7 +33,7 @@ The Google Sign-In SDK allows users to sign in with their Google account from th ] s.ios.framework = 'UIKit' s.osx.framework = 'AppKit' - s.dependency 'FirebaseAppCheck', '~> 10.0' + s.dependency 'AppCheckCore', '~> 0.1.0-alpha' s.dependency 'AppAuth', '~> 1.6' s.dependency 'GTMAppAuth', '~> 4.0' s.dependency 'GTMSessionFetcher/Core', '>= 1.1', '< 4.0' diff --git a/GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h b/GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h deleted file mode 100644 index 7f934ec7..00000000 --- a/GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2023 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 - -NS_ASSUME_NONNULL_BEGIN - -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -@protocol GIDAppCheckTokenFetcher; -@class FIRAppCheckToken; - -/// Interface providing the API for both pre-warming `GIDSignIn` to use Firebase App Check and -/// fetching the App Check token. -NS_AVAILABLE_IOS(14) -@protocol GIDAppCheckProvider - -/// Creates the instance of this App Check wrapper class. -/// -/// @param tokenFetcher The instance performing the Firebase App Check token requests. If `provider` -/// is nil, then we default to `FIRAppCheck`. -/// @param userDefaults The instance of `NSUserDefaults` that `GIDAppCheck` will use to store its -/// preparation status. If nil, `GIDAppCheck` will use `-[NSUserDefaults standardUserDefaults]`. -- (instancetype)initWithAppCheckTokenFetcher:(nullable id)tokenFetcher - userDefaults:(nullable NSUserDefaults *)userDefaults; - -/// Prewarms the library for App Check by asking Firebase App Check to generate the App Attest key -/// id and perform the initial attestation process (if needed). -/// -/// @param completion A `nullable` callback with a `nullable` `NSError` if preparation fails. -- (void)prepareForAppCheckWithCompletion:(nullable void (^)(NSError * _Nullable error))completion; - -/// Fetches the limited use Firebase token. -/// -/// @param completion A `nullable` callback with the `FIRAppCheckToken` if present, or an `NSError` -/// otherwise. -- (void)getLimitedUseTokenWithCompletion:(nullable void (^)(FIRAppCheckToken * _Nullable token, - NSError * _Nullable error))completion; - -/// Whether or not the App Attest key ID created and the attestation object has been fetched. -- (BOOL)isPrepared; - -@end - -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - -NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h b/GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h similarity index 59% rename from GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h rename to GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h index ad994a92..2f0d64b8 100644 --- a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h +++ b/GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h @@ -16,26 +16,25 @@ #import #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/API/GIDAppCheckTokenFetcher.h" +#import -@class FIRAppCheckToken; +@class GACAppCheckToken; NS_ASSUME_NONNULL_BEGIN -extern NSUInteger const kGIDAppCheckTokenFetcherTokenError; +extern NSUInteger const kGIDAppCheckProviderFakeError; NS_CLASS_AVAILABLE_IOS(14) -@interface GIDAppCheckTokenFetcherFake : NSObject +@interface GIDAppCheckProviderFake : NSObject -/// Creates an instance with the provided app check token and error. +/// Creates an instance conforming to `GACAppCheckProvider` with the provided app check token and +/// error. /// -/// This protocol is mainly used for testing purposes so that the token fetching from Firebase App -/// Check can be faked. -/// @param token The `FIRAppCheckToken` to pass into the completion called from -/// `limitedUseTokenWithCompletion:`. +/// @param token The `GACAppCheckToken` instance to pass into the completion called from +/// `getTokenWithCompletion:`. /// @param error The `NSError` to pass into the completion called from -/// `limitedUseTokenWithCompletion:`. -- (instancetype)initWithAppCheckToken:(nullable FIRAppCheckToken *)token +/// `getTokenWithCompletion:`. +- (instancetype)initWithAppCheckToken:(nullable GACAppCheckToken *)token error:(nullable NSError *)error; @end diff --git a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.m b/GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.m similarity index 60% rename from GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.m rename to GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.m index 20719a9e..8dc61095 100644 --- a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.m +++ b/GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.m @@ -12,25 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import +#import "GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h" #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h" -@import FirebaseAppCheck; +#import -NSUInteger const kGIDAppCheckTokenFetcherTokenError = 1; +NSUInteger const kGIDAppCheckProviderFakeError = 1; -@interface GIDAppCheckTokenFetcherFake () +@interface GIDAppCheckProviderFake () -@property(nonatomic, strong, nullable) FIRAppCheckToken *token; +@property(nonatomic, strong, nullable) id token; @property(nonatomic, strong, nullable) NSError *error; @end -@implementation GIDAppCheckTokenFetcherFake +@implementation GIDAppCheckProviderFake -- (instancetype)initWithAppCheckToken:(nullable FIRAppCheckToken *)token +- (instancetype)initWithAppCheckToken:(nullable id)token error:(nullable NSError *)error { if (self = [super init]) { _token = token; @@ -39,10 +38,10 @@ - (instancetype)initWithAppCheckToken:(nullable FIRAppCheckToken *)token return self; } -- (void)limitedUseTokenWithCompletion:(void (^)(FIRAppCheckToken * _Nullable, - NSError * _Nullable))completion { +- (void)getTokenWithCompletion:(nonnull void (^)(GACAppCheckToken * _Nullable, + NSError * _Nullable))handler { dispatch_async(dispatch_get_main_queue(), ^{ - completion(self.token, self.error); + handler(self.token, self.error); }); } diff --git a/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h b/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h index 96d63ea2..68d0a44e 100644 --- a/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h +++ b/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h @@ -19,17 +19,50 @@ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import -#import "GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h" NS_ASSUME_NONNULL_BEGIN -@class FIRAppCheckToken; +@protocol GACAppCheckProvider; +@protocol GACAppCheckTokenProtocol; + extern NSString *const kGIDAppCheckPreparedKey; NS_CLASS_AVAILABLE_IOS(14) -@interface GIDAppCheck : NSObject +@interface GIDAppCheck : NSObject + +/// Creates the instance of this App Check wrapper class. +/// +/// The instance is created using `+[NSUserDefaults standardUserDefaults]` and the standard App +/// Check provider. +/// +/// @SeeAlso The App Check provider is constructed with `+[GIDAppCheck standardAppCheckProvider]`. +- (instancetype)init; + +/// Creates the instance of this App Check wrapper class. +/// +/// @param appCheckProvider The instance performing the Firebase App Check token requests. If `nil`, +/// then a default implementation will be used. +/// @param userDefaults The instance of `NSUserDefaults` that `GIDAppCheck` will use to store its +/// preparation status. If nil, `GIDAppCheck` will use `-[NSUserDefaults standardUserDefaults]`. +- (instancetype)initWithAppCheckProvider:(id)appCheckProvider + userDefaults:(NSUserDefaults *)userDefaults NS_DESIGNATED_INITIALIZER; + +/// Prewarms the library for App Check by asking Firebase App Check to generate the App Attest key +/// id and perform the initial attestation process (if needed). +/// +/// @param completion A `nullable` callback with a `nullable` `NSError` if preparation fails. +- (void)prepareForAppCheckWithCompletion:(nullable void (^)(NSError * _Nullable error))completion; + +/// Fetches the limited use Firebase token. +/// +/// @param completion A `nullable` callback with the `FIRAppCheckToken` if present, or an `NSError` +/// otherwise. +- (void)getLimitedUseTokenWithCompletion: + (nullable void (^)(id _Nullable token, + NSError * _Nullable error))completion; -- (instancetype)init NS_UNAVAILABLE; +/// Whether or not the App Attest key ID created and the attestation object has been fetched. +- (BOOL)isPrepared; @end diff --git a/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.m b/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.m index 1b7a8095..3ef6e05b 100644 --- a/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.m +++ b/GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.m @@ -15,23 +15,32 @@ */ #import "GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h" -#import "GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h" -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/FIRAppCheck+GIDAppCheckTokenFetcher.h" -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDAppCheckError.h" - -@import FirebaseAppCheck; #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST +#import +#import +#import +#import + +#import "GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDAppCheckError.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" + NSErrorDomain const kGIDAppCheckErrorDomain = @"com.google.GIDAppCheck"; NSString *const kGIDAppCheckPreparedKey = @"com.google.GIDAppCheckPreparedKey"; +static NSString *const kGIDConfigClientIDKey = @"GIDClientID"; +static NSString *const kGIDAppAttestServiceName = @"GoogleSignIn-iOS"; +static NSString *const kGIDAppAttestResourceNameFormat = @"oauthClients/%@"; +static NSString *const kGIDAppAttestBaseURL = @"https://firebaseappcheck.googleapis.com/v1beta"; typedef void (^GIDAppCheckPrepareCompletion)(NSError * _Nullable); -typedef void (^GIDAppCheckTokenCompletion)(FIRAppCheckToken * _Nullable, NSError * _Nullable); +typedef void (^GIDAppCheckTokenCompletion)(id _Nullable, + NSError * _Nullable); @interface GIDAppCheck () -@property(nonatomic, strong) id tokenFetcher; +@property(nonatomic, strong) GACAppCheck *appCheck; @property(nonatomic, strong) dispatch_queue_t workerQueue; @property(nonatomic, strong) NSUserDefaults *userDefaults; @property(atomic, strong) NSMutableArray *prepareCompletions; @@ -41,11 +50,23 @@ @interface GIDAppCheck () @implementation GIDAppCheck -- (instancetype)initWithAppCheckTokenFetcher:(nullable id)tokenFetcher - userDefaults:(nullable NSUserDefaults *)userDefaults { +- (instancetype)init { + id provider = [GIDAppCheck standardAppCheckProvider]; + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + return [self initWithAppCheckProvider:provider userDefaults:userDefaults]; +} + +- (instancetype)initWithAppCheckProvider:(id)appCheckProvider + userDefaults:(NSUserDefaults *)userDefaults { if (self = [super init]) { - _tokenFetcher = tokenFetcher ?: [FIRAppCheck appCheck]; - _userDefaults = userDefaults ?: [NSUserDefaults standardUserDefaults]; + _appCheck = [[GACAppCheck alloc] initWithServiceName:kGIDConfigClientIDKey + resourceName:[GIDAppCheck appAttestResourceName] + appCheckProvider:appCheckProvider + settings:[[GACAppCheckSettings alloc] init] + tokenDelegate:nil + keychainAccessGroup:nil]; + + _userDefaults = userDefaults; _workerQueue = dispatch_queue_create("com.google.googlesignin.GIDAppCheckWorkerQueue", nil); _prepareCompletions = [NSMutableArray array]; _preparing = NO; @@ -89,8 +110,8 @@ - (void)prepareForAppCheckWithCompletion:(nullable GIDAppCheckPrepareCompletion) return; } - [self.tokenFetcher limitedUseTokenWithCompletion:^(FIRAppCheckToken * _Nullable token, - NSError * _Nullable error) { + [self.appCheck getLimitedUseTokenWithCompletion:^(id _Nullable token, + NSError * _Nullable error) { NSError * __block maybeError = error; @synchronized (self) { if (!token && !error) { @@ -118,8 +139,8 @@ - (void)prepareForAppCheckWithCompletion:(nullable GIDAppCheckPrepareCompletion) - (void)getLimitedUseTokenWithCompletion:(nullable GIDAppCheckTokenCompletion)completion { dispatch_async(self.workerQueue, ^{ - [self.tokenFetcher limitedUseTokenWithCompletion:^(FIRAppCheckToken * _Nullable token, - NSError * _Nullable error) { + [self.appCheck getLimitedUseTokenWithCompletion:^(id _Nullable token, + NSError * _Nullable error) { if (token) { [self.userDefaults setBool:YES forKey:kGIDAppCheckPreparedKey]; } @@ -130,6 +151,21 @@ - (void)getLimitedUseTokenWithCompletion:(nullable GIDAppCheckTokenCompletion)co }); } ++ (NSString *)appAttestResourceName { + NSString *clientID = [NSBundle.mainBundle objectForInfoDictionaryKey:kGIDConfigClientIDKey]; + return [NSString stringWithFormat:kGIDAppAttestResourceNameFormat, clientID]; +} + ++ (id)standardAppCheckProvider { + return [[GACAppAttestProvider alloc] initWithServiceName:kGIDAppAttestServiceName + resourceName:[GIDAppCheck appAttestResourceName] + baseURL:kGIDAppAttestBaseURL + APIKey:nil + keychainAccessGroup:nil + limitedUse:YES + requestHooks:nil]; +} + @end #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/API/GIDAppCheckTokenFetcher.h b/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/API/GIDAppCheckTokenFetcher.h deleted file mode 100644 index 57af940e..00000000 --- a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/API/GIDAppCheckTokenFetcher.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 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. - */ - -NS_ASSUME_NONNULL_BEGIN - -@class FIRAppCheckToken; - -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - -NS_AVAILABLE_IOS(14) -@protocol GIDAppCheckTokenFetcher - -/// Get the limited use `FIRAppCheckToken`. -/// -/// @param completion A block that passes back the `FIRAppCheckToken` upon success or an error in -/// the case of any failure. -- (void)limitedUseTokenWithCompletion:(nullable void (^)(FIRAppCheckToken * _Nullable token, - NSError * _Nullable error))completion; - -@end - -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - -NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/FIRAppCheck+GIDAppCheckTokenFetcher.h b/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/FIRAppCheck+GIDAppCheckTokenFetcher.h deleted file mode 100644 index 0ec82aeb..00000000 --- a/GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/FIRAppCheck+GIDAppCheckTokenFetcher.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2023 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 FirebaseAppCheck; -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/API/GIDAppCheckTokenFetcher.h" - -NS_ASSUME_NONNULL_BEGIN - -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - -@interface FIRAppCheck (FIRAppCheck_GIDAppCheckTokenFetcher) -@end - -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - -NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 25080d1c..d2ea2175 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -28,10 +28,9 @@ #import "GoogleSignIn/Sources/GIDScopes.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import "FirebaseAppCheck/FIRAppCheckToken.h" -#import "GoogleSignIn/Sources/GIDAppCheck/UI/GIDActivityIndicatorViewController.h" +#import #import "GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h" -#import "GoogleSignIn/Sources/GIDAppCheck/API/GIDAppCheckProvider.h" +#import "GoogleSignIn/Sources/GIDAppCheck/UI/GIDActivityIndicatorViewController.h" #import "GoogleSignIn/Sources/GIDAuthStateMigration.h" #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -170,7 +169,7 @@ @implementation GIDSignIn { // represent a sign in continuation. GIDSignInInternalOptions *_currentOptions; #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - id _appCheck API_AVAILABLE(ios(14)); + GIDAppCheck *_appCheck API_AVAILABLE(ios(14)); #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST // AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; @@ -460,10 +459,9 @@ + (GIDSignIn *)sharedInstance { [[GTMKeychainStore alloc] initWithItemName:kGTMAppAuthKeychainName]; #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST if (@available(iOS 14.0, *)) { - GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:nil - userDefaults:nil]; + GIDAppCheck *appCheck = [[GIDAppCheck alloc] init]; sharedInstance = [[self alloc] initWithKeychainStore:keychainStore - appCheckProvider:appCheck]; + appCheck:appCheck]; } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST if (!sharedInstance) { @@ -479,9 +477,9 @@ + (GIDSignIn *)sharedInstance { - (void)configureWithCompletion:(nullable void (^)(NSError * _Nullable))completion { @synchronized(self) { [_appCheck prepareForAppCheckWithCompletion:^(NSError * _Nullable error) { - if (completion) { - completion(error); - } + if (completion) { + completion(error); + } }]; } } @@ -531,10 +529,10 @@ - (instancetype)initWithKeychainStore:(GTMKeychainStore *)keychainStore { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (instancetype)initWithKeychainStore:(GTMKeychainStore *)keychainStore - appCheckProvider:(id)appCheckProvider { + appCheck:(GIDAppCheck *)appCheck { self = [self initWithKeychainStore:keychainStore]; if (self) { - _appCheck = appCheckProvider; + _appCheck = appCheck; } return self; } @@ -646,7 +644,7 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp dispatch_time_t halfSecond = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC / 2); dispatch_after(halfSecond, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self->_appCheck getLimitedUseTokenWithCompletion: - ^(FIRAppCheckToken * _Nullable token, NSError * _Nullable error) { + ^(id _Nullable token, NSError * _Nullable error) { if (token) { additionalParameters[kClientAssertionTypeParameter] = kClientAssertionTypeParameterValue; diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 7210ecd8..4072a4a0 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN @class GIDGoogleUser; @class GIDSignInInternalOptions; @class GTMKeychainStore; -@protocol GIDAppCheckProvider; +@class GIDAppCheck; /// Represents a completion block that takes a `GIDSignInResult` on success or an error if the /// operation was unsuccessful. @@ -51,7 +51,7 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// Private initializer taking a `GTMKeychainStore` and `GIDAppCheckProvider`. - (instancetype)initWithKeychainStore:(GTMKeychainStore *)keychainStore - appCheckProvider:(id)appCheckProvider + appCheck:(GIDAppCheck *)appCheck API_AVAILABLE(ios(14)); #endif // TARGET_OS_IOS || !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 7bc0014a..e6bd3407 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -26,7 +26,6 @@ @class GIDConfiguration; @class GIDGoogleUser; @class GIDSignInResult; -@protocol GIDAppCheckProvider; NS_ASSUME_NONNULL_BEGIN diff --git a/GoogleSignIn/Tests/Unit/GIDAppCheckTest.m b/GoogleSignIn/Tests/Unit/GIDAppCheckTest.m index f4e49d26..e84c9a84 100644 --- a/GoogleSignIn/Tests/Unit/GIDAppCheckTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAppCheckTest.m @@ -17,13 +17,13 @@ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import -#import "FirebaseAppCheck/FIRAppCheckToken.h" +#import #import "GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h" -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h" +#import "GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDAppCheckError.h" static NSUInteger const timeout = 1; -static NSString *const kUserDefaultsSuiteName = @"GIDAppCheckKeySuiteName"; +static NSString *const kUserDefaultsTestSuiteName = @"GIDAppCheckTestKeySuiteName"; NS_CLASS_AVAILABLE_IOS(14) @interface GIDAppCheckTest : XCTestCase @@ -36,27 +36,28 @@ @implementation GIDAppCheckTest - (void)setUp { [super setUp]; - _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kUserDefaultsSuiteName]; + _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kUserDefaultsTestSuiteName]; } - (void)tearDown { [super tearDown]; [self.userDefaults removeObjectForKey:kGIDAppCheckPreparedKey]; - [self.userDefaults removeSuiteNamed:kUserDefaultsSuiteName]; + [self.userDefaults removeSuiteNamed:kUserDefaultsTestSuiteName]; } - (void)testGetLimitedUseTokenFailure { XCTestExpectation *tokenFailExpectation = [self expectationWithDescription:@"App check token fail"]; NSError *expectedError = [NSError errorWithDomain:kGIDAppCheckErrorDomain - code:kGIDAppCheckTokenFetcherTokenError + code:kGIDAppCheckProviderFakeError userInfo:nil]; - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:nil error:expectedError]; - GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:self.userDefaults]; - [appCheck getLimitedUseTokenWithCompletion:^(FIRAppCheckToken * _Nullable token, + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:nil error:expectedError]; + GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:self.userDefaults]; + + [appCheck getLimitedUseTokenWithCompletion:^(id _Nullable token, NSError * _Nullable error) { XCTAssertNil(token); XCTAssertEqualObjects(expectedError, error); @@ -70,13 +71,14 @@ - (void)testIsPreparedError { XCTestExpectation *notAlreadyPreparedExpectation = [self expectationWithDescription:@"App check not already prepared error"]; - FIRAppCheckToken *expectedToken = [[FIRAppCheckToken alloc] initWithToken:@"foo" + GACAppCheckToken *expectedToken = [[GACAppCheckToken alloc] initWithToken:@"foo" expirationDate:[NSDate distantFuture]]; // It doesn't matter what we pass for the error since we will check `isPrepared` and make one - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:expectedToken error:nil]; - GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:self.userDefaults]; + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:expectedToken error:nil]; + + GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:self.userDefaults]; [appCheck prepareForAppCheckWithCompletion:^(NSError * _Nullable error) { XCTAssertNil(error); @@ -88,6 +90,7 @@ - (void)testIsPreparedError { XCTestExpectation *alreadyPreparedExpectation = [self expectationWithDescription:@"App check already prepared error"]; + // Should be no error since multiple calls to prepare should be fine. [appCheck prepareForAppCheckWithCompletion:^(NSError * _Nullable error) { XCTAssertNil(error); [alreadyPreparedExpectation fulfill]; @@ -101,13 +104,14 @@ - (void)testIsPreparedError { - (void)testGetLimitedUseTokenSucceeds { XCTestExpectation *prepareExpectation = [self expectationWithDescription:@"Prepare for App Check expectation"]; - FIRAppCheckToken *expectedToken = [[FIRAppCheckToken alloc] initWithToken:@"foo" + + GACAppCheckToken *expectedToken = [[GACAppCheckToken alloc] initWithToken:@"foo" expirationDate:[NSDate distantFuture]]; - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:expectedToken error:nil]; - GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:self.userDefaults]; + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:expectedToken error:nil]; + GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:self.userDefaults]; [appCheck prepareForAppCheckWithCompletion:^(NSError * _Nullable error) { XCTAssertNil(error); @@ -122,7 +126,7 @@ - (void)testGetLimitedUseTokenSucceeds { XCTestExpectation *getLimitedUseTokenSucceedsExpectation = [self expectationWithDescription:@"getLimitedUseToken should succeed"]; - [appCheck getLimitedUseTokenWithCompletion:^(FIRAppCheckToken * _Nullable token, + [appCheck getLimitedUseTokenWithCompletion:^(id _Nullable token, NSError * _Nullable error) { XCTAssertNil(error); XCTAssertNotNil(token); @@ -142,13 +146,13 @@ - (void)testAsyncCompletions { XCTestExpectation *secondPrepareExpectation = [self expectationWithDescription:@"Second async prepare for App Check expectation"]; - FIRAppCheckToken *expectedToken = [[FIRAppCheckToken alloc] initWithToken:@"foo" + GACAppCheckToken *expectedToken = [[GACAppCheckToken alloc] initWithToken:@"foo" expirationDate:[NSDate distantFuture]]; - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:expectedToken error:nil]; - GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:self.userDefaults]; + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:expectedToken error:nil]; + GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:self.userDefaults]; dispatch_async(dispatch_get_main_queue(), ^{ [appCheck prepareForAppCheckWithCompletion:^(NSError * _Nullable error) { diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index a0777ddb..400e09fb 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -34,9 +34,9 @@ #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -#import "FirebaseAppCheck/FIRAppCheckToken.h" +#import #import "GoogleSignIn/Sources/GIDAppCheck/Implementations/GIDAppCheck.h" -#import "GoogleSignIn/Sources/GIDAppCheckTokenFetcher/Implementations/GIDAppCheckTokenFetcherFake.h" +#import "GoogleSignIn/Sources/GIDAppCheck/Implementations/Fake/GIDAppCheckProviderFake.h" #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -389,23 +389,22 @@ - (void)testConfigureSucceeds { XCTestExpectation *configureSucceedsExpecation = [self expectationWithDescription:@"Configure succeeds expectation"]; - FIRAppCheckToken *token = [[FIRAppCheckToken alloc] initWithToken:@"foo" + GACAppCheckToken *token = [[GACAppCheckToken alloc] initWithToken:@"foo" expirationDate:[NSDate distantFuture]]; - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:token error:nil]; - GIDAppCheck *appCheckProvider = - [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:_testUserDefaults]; + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:token error:nil]; + GIDAppCheck *appCheck = [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:_testUserDefaults]; GIDSignIn *signIn = [[GIDSignIn alloc] initWithKeychainStore:_keychainStore - appCheckProvider:appCheckProvider]; + appCheck:appCheck]; [signIn configureWithCompletion:^(NSError * _Nullable error) { XCTAssertNil(error); [configureSucceedsExpecation fulfill]; }]; [self waitForExpectations:@[configureSucceedsExpecation] timeout:1]; - XCTAssertTrue(appCheckProvider.isPrepared); + XCTAssertTrue(appCheck.isPrepared); } } @@ -414,14 +413,14 @@ - (void)testConfigureFailsNoTokenOrError { XCTestExpectation *configureFailsExpecation = [self expectationWithDescription:@"Configure fails expectation"]; - GIDAppCheckTokenFetcherFake *tokenFetcher = - [[GIDAppCheckTokenFetcherFake alloc] initWithAppCheckToken:nil error:nil]; - GIDAppCheck *appCheckProvider = - [[GIDAppCheck alloc] initWithAppCheckTokenFetcher:tokenFetcher - userDefaults:_testUserDefaults]; + GIDAppCheckProviderFake *fakeProvider = + [[GIDAppCheckProviderFake alloc] initWithAppCheckToken:nil error:nil]; + GIDAppCheck *appCheck = + [[GIDAppCheck alloc] initWithAppCheckProvider:fakeProvider + userDefaults:_testUserDefaults]; GIDSignIn *signIn = [[GIDSignIn alloc] initWithKeychainStore:_keychainStore - appCheckProvider:appCheckProvider]; + appCheck:appCheck]; // `configureWithCompletion:` should fail if neither a token or error is present [signIn configureWithCompletion:^(NSError * _Nullable error) { @@ -431,7 +430,7 @@ - (void)testConfigureFailsNoTokenOrError { }]; [self waitForExpectations:@[configureFailsExpecation] timeout:1]; - XCTAssertFalse(appCheckProvider.isPrepared); + XCTAssertFalse(appCheck.isPrepared); } } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/Package.swift b/Package.swift index 7b4c4ab0..cd74c50d 100644 --- a/Package.swift +++ b/Package.swift @@ -46,9 +46,9 @@ let package = Package( url: "https://github.com/openid/AppAuth-iOS.git", "1.6.0" ..< "2.0.0"), .package( - name: "Firebase", - url: "https://github.com/firebase/firebase-ios-sdk.git", - "10.0.0" ..< "11.0.0"), + name: "AppCheck", + url: "https://github.com/google/app-check.git", + .branch("main")), .package( name: "GTMAppAuth", url: "https://github.com/google/GTMAppAuth.git", @@ -71,7 +71,7 @@ let package = Package( name: "GoogleSignIn", dependencies: [ .product(name: "AppAuth", package: "AppAuth"), - .product(name: "FirebaseAppCheck", package: "Firebase"), + .product(name: "AppCheckCore", package: "AppCheck"), .product(name: "GTMAppAuth", package: "GTMAppAuth"), .product(name: "GTMSessionFetcherCore", package: "GTMSessionFetcher"), ], @@ -108,7 +108,7 @@ let package = Package( "GoogleSignIn", "OCMock", .product(name: "AppAuth", package: "AppAuth"), - .product(name: "FirebaseAppCheck", package: "Firebase"), + .product(name: "AppCheckCore", package: "AppCheck"), .product(name: "GTMAppAuth", package: "GTMAppAuth"), .product(name: "GTMSessionFetcherCore", package: "GTMSessionFetcher"), .product(name: "GULMethodSwizzler", package: "GoogleUtilities"), diff --git a/Samples/Swift/AppAttestExample/AppAttestExample.xcodeproj/project.pbxproj b/Samples/Swift/AppAttestExample/AppAttestExample.xcodeproj/project.pbxproj index 344a6773..342a46fe 100644 --- a/Samples/Swift/AppAttestExample/AppAttestExample.xcodeproj/project.pbxproj +++ b/Samples/Swift/AppAttestExample/AppAttestExample.xcodeproj/project.pbxproj @@ -12,8 +12,6 @@ 73A464042A1C3B3400BA8528 /* AppAttestExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A464032A1C3B3400BA8528 /* AppAttestExampleApp.swift */; }; 73A464062A1C3B3400BA8528 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A464052A1C3B3400BA8528 /* ContentView.swift */; }; 73A4640B2A1C3B3500BA8528 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 73A4640A2A1C3B3500BA8528 /* Preview Assets.xcassets */; }; - 73BC0EB22A57609D00C3DDE5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 73BC0EB12A57609D00C3DDE5 /* GoogleService-Info.plist */; }; - 73BD4BB52A390CFE00A48E3C /* BirthdayAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BD4BB42A390CFE00A48E3C /* BirthdayAppCheckProviderFactory.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,8 +22,6 @@ 73A464032A1C3B3400BA8528 /* AppAttestExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAttestExampleApp.swift; sourceTree = ""; }; 73A464052A1C3B3400BA8528 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 73A4640A2A1C3B3500BA8528 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 73BC0EB12A57609D00C3DDE5 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 73BD4BB42A390CFE00A48E3C /* BirthdayAppCheckProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BirthdayAppCheckProviderFactory.swift; sourceTree = ""; }; 7D9832F2FFAF408698660CA8 /* Pods-AppAttestExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppAttestExample.debug.xcconfig"; path = "Target Support Files/Pods-AppAttestExample/Pods-AppAttestExample.debug.xcconfig"; sourceTree = ""; }; 91F3A930BB86D9E0648046BC /* Pods_AppAttestExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppAttestExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -74,10 +70,8 @@ children = ( 73443A232A55F56900A4932E /* AppAttestExample.entitlements */, 73A464032A1C3B3400BA8528 /* AppAttestExampleApp.swift */, - 73BD4BB42A390CFE00A48E3C /* BirthdayAppCheckProviderFactory.swift */, 73A464052A1C3B3400BA8528 /* ContentView.swift */, 738D5F722A26BC3B00A7F11B /* BirthdayLoader.swift */, - 73BC0EB12A57609D00C3DDE5 /* GoogleService-Info.plist */, 73A464092A1C3B3500BA8528 /* Preview Content */, ); path = AppAttestExample; @@ -160,7 +154,6 @@ buildActionMask = 2147483647; files = ( 73A4640B2A1C3B3500BA8528 /* Preview Assets.xcassets in Resources */, - 73BC0EB22A57609D00C3DDE5 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -215,7 +208,6 @@ files = ( 738D5F732A26BC3B00A7F11B /* BirthdayLoader.swift in Sources */, 73A464062A1C3B3400BA8528 /* ContentView.swift in Sources */, - 73BD4BB52A390CFE00A48E3C /* BirthdayAppCheckProviderFactory.swift in Sources */, 73A464042A1C3B3400BA8528 /* AppAttestExampleApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Samples/Swift/AppAttestExample/AppAttestExample/AppAttestExampleApp.swift b/Samples/Swift/AppAttestExample/AppAttestExample/AppAttestExampleApp.swift index cdaa5db2..a540b533 100644 --- a/Samples/Swift/AppAttestExample/AppAttestExample/AppAttestExampleApp.swift +++ b/Samples/Swift/AppAttestExample/AppAttestExample/AppAttestExampleApp.swift @@ -15,8 +15,6 @@ */ import SwiftUI -import FirebaseCore -import FirebaseAppCheck import GoogleSignIn class AppDelegate: NSObject, UIApplicationDelegate { @@ -24,14 +22,6 @@ class AppDelegate: NSObject, UIApplicationDelegate { _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { - #if targetEnvironment(simulator) - let debugProvider = AppCheckDebugProviderFactory() - AppCheck.setAppCheckProviderFactory(debugProvider) - #else - AppCheck.setAppCheckProviderFactory(BirthdayAppCheckProviderFactory()) - #endif - FirebaseApp.configure() - GIDSignIn.sharedInstance.configureWithCompletion { error in if let error { print("Error configuring `GIDSignIn` for Firebase App Check: \(error)") diff --git a/Samples/Swift/AppAttestExample/AppAttestExample/BirthdayAppCheckProviderFactory.swift b/Samples/Swift/AppAttestExample/AppAttestExample/BirthdayAppCheckProviderFactory.swift deleted file mode 100644 index baf501b0..00000000 --- a/Samples/Swift/AppAttestExample/AppAttestExample/BirthdayAppCheckProviderFactory.swift +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 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 FirebaseCore -import FirebaseAppCheck - -class BirthdayAppCheckProviderFactory: NSObject, AppCheckProviderFactory { - func createProvider(with app: FirebaseApp) -> AppCheckProvider? { - return AppAttestProvider(app: app) - } -} - diff --git a/Samples/Swift/AppAttestExample/AppAttestExample/Info.plist b/Samples/Swift/AppAttestExample/AppAttestExample/Info.plist new file mode 100644 index 00000000..b9179a51 --- /dev/null +++ b/Samples/Swift/AppAttestExample/AppAttestExample/Info.plist @@ -0,0 +1,21 @@ + + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.googleusercontent.apps.665845761721-a9g0c1k6buv131av6nnmburou5scd63h + CFBundleURLSchemes + + com.googleusercontent.apps.665845761721-a9g0c1k6buv131av6nnmburou5scd63h + + + + GIDClientID + 665845761721-a9g0c1k6buv131av6nnmburou5scd63h.apps.googleusercontent.com + + diff --git a/Samples/Swift/AppAttestExample/Podfile b/Samples/Swift/AppAttestExample/Podfile index a99c529f..2a5c41a5 100644 --- a/Samples/Swift/AppAttestExample/Podfile +++ b/Samples/Swift/AppAttestExample/Podfile @@ -5,8 +5,6 @@ project 'AppAttestExample.xcodeproj' use_frameworks! :linkage => :static target 'AppAttestExample' do + pod 'AppCheckCore', :git => 'https://github.com/google/app-check.git', :tag => 'CocoaPods-0.1.0-alpha.1' platform :ios, '14.0' - - pod 'FirebaseCore', '~> 10.0' - pod 'FirebaseAppCheck', '~> 10.0' end