From 032b0800d398a4c71d0e823f983051e71396dbab Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Fri, 23 Sep 2022 15:14:12 -0700 Subject: [PATCH 01/10] Add core Info.plist config functionality and update API surface. --- GoogleSignIn/Sources/GIDSignIn.m | 98 ++++++++++++------- .../Sources/Public/GoogleSignIn/GIDSignIn.h | 63 +++++------- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 65 ++++++------ .../ObjC/SignInSample/SignInSample-Info.plist | 3 + .../Source/SignInViewController.m | 16 +-- .../project.pbxproj | 19 +++- .../Services/GoogleSignInAuthenticator.swift | 19 +--- .../Swift/DaysUntilBirthday/iOS/Info.plist | 3 + .../Swift/DaysUntilBirthday/macOS/Info.plist | 3 + 9 files changed, 149 insertions(+), 140 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 8cfc3d60..490cc396 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -135,6 +135,12 @@ // Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; +// Info.plist config keys +static NSString *const kConfigClientIDKey = @"GIDClientID"; +static NSString *const kConfigServerClientIDKey = @"GIDServerClientID"; +static NSString *const kConfigHostedDomainKey = @"GIDHostedDomain"; +static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm"; + // The callback queue used for authentication flow. @interface GIDAuthFlow : GIDCallbackQueue @@ -214,12 +220,11 @@ - (BOOL)restorePreviousSignInNoRefresh { #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion { +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingViewController:presentingViewController loginHint:hint addScopesFlow:NO @@ -227,13 +232,12 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration [self signInWithOptions:options]; } -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion { +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingViewController:presentingViewController loginHint:hint addScopesFlow:NO @@ -242,13 +246,11 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration [self signInWithOptions:options]; } -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion { - [self signInWithConfiguration:configuration - presentingViewController:presentingViewController - hint:nil - completion:completion]; +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + completion:(nullable GIDSignInCompletion)completion { + [self signInWithPresentingViewController:presentingViewController + hint:nil + completion:completion]; } - (void)addScopes:(NSArray *)scopes @@ -307,12 +309,11 @@ - (void)addScopes:(NSArray *)scopes #elif TARGET_OS_OSX -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion { +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingWindow:presentingWindow loginHint:hint addScopesFlow:NO @@ -320,22 +321,19 @@ - (void)signInWithConfiguration:(GIDConfiguration *)configuration [self signInWithOptions:options]; } -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion { - [self signInWithConfiguration:configuration - presentingWindow:presentingWindow - hint:nil - completion:completion]; +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + completion:(nullable GIDSignInCompletion)completion { + [self signInWithPresentingWindow:presentingWindow + hint:nil + completion:completion]; } -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion { +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + completion:(nullable GIDSignInCompletion)completion { GIDSignInInternalOptions *options = - [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingWindow:presentingWindow loginHint:hint addScopesFlow:NO @@ -477,6 +475,26 @@ + (GIDSignIn *)sharedInstance { - (id)initPrivate { self = [super init]; if (self) { + // Get the Info.plist dictionary from the app's main bundle. + NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + + NSString *clientID = infoDictionary[kConfigClientIDKey]; + NSString *serverClientID = infoDictionary[kConfigServerClientIDKey]; + NSString *hostedDomain = infoDictionary[kConfigHostedDomainKey]; + NSString *openIDRealm = infoDictionary[kConfigOpenIDRealmKey]; + + GIDConfiguration *configuration; + + // We need at least a client ID to create a configuration. + if (clientID) { + configuration = [[GIDConfiguration alloc] initWithClientID:clientID + serverClientID:serverClientID + hostedDomain:hostedDomain + openIDRealm:openIDRealm]; + // Set the initial active configuation + _configuration = configuration; + } + // Check to see if the 3P app is being run for the first time after a fresh install. BOOL isFreshInstall = [self isFreshInstall]; @@ -514,6 +532,14 @@ - (void)signInWithOptions:(GIDSignInInternalOptions *)options { } if (options.interactive) { + // Ensure that a configuration has been provided. + if (!_configuration) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"No active configuration. Make sure GIDClientID is set in Info.plist."]; + return; + } + // Explicitly throw exception for missing client ID here. This must come before // scheme check because schemes rely on reverse client IDs. [self assertValidParameters]; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 35a8a15d..41a059d7 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -69,6 +69,9 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// The `GIDGoogleUser` object representing the current user or `nil` if there is no signed-in user. @property(nonatomic, readonly, nullable) GIDGoogleUser *currentUser; +/// The active configuration for this instance of `GIDSignIn`. +@property(nonatomic, nullable) GIDConfiguration *configuration; + /// Unavailable. Use the `sharedInstance` property to instantiate `GIDSignIn`. /// :nodoc: + (instancetype)new NS_UNAVAILABLE; @@ -106,32 +109,29 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); - (void)disconnectWithCompletion:(nullable GIDDisconnectCompletion)completion; #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -/// Starts an interactive sign-in flow on iOS using the provided configuration. +/// Starts an interactive sign-in flow on iOS. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingViewController The view controller used to present `SFSafariViewContoller` on /// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on /// iOS 13+. /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - completion:(nullable GIDSignInCompletion)completion +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + completion:(nullable GIDSignInCompletion)completion NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); -/// Starts an interactive sign-in flow on iOS using the provided configuration and a login hint. +/// Starts an interactive sign-in flow on iOS using the provided hint. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingViewController The view controller used to present `SFSafariViewContoller` on /// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on /// iOS 13+. @@ -139,20 +139,18 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// address, to be prefilled if possible. /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + completion:(nullable GIDSignInCompletion)completion NS_EXTENSION_UNAVAILABLE("The sign-in flow is not supported in App Extensions."); -/// Starts an interactive sign-in flow on iOS using the provided configuration and a login hint. +/// Starts an interactive sign-in flow on iOS using the provided hint and additional scopes. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingViewController The view controller used to present `SFSafariViewContoller` on /// iOS 9 and 10. /// @param hint An optional hint for the authorization server, for example the user's ID or email @@ -161,11 +159,10 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion; +- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + completion:(nullable GIDSignInCompletion)completion; /// Starts an interactive consent flow on iOS to add scopes to the current user's grants. /// @@ -184,47 +181,42 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); NS_EXTENSION_UNAVAILABLE("The add scopes flow is not supported in App Extensions."); #elif TARGET_OS_OSX -/// Starts an interactive sign-in flow on macOS using the provided configuration. +/// Starts an interactive sign-in flow on macOS. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable GIDSignInCompletion)completion; +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + completion:(nullable GIDSignInCompletion)completion; -/// Starts an interactive sign-in flow on macOS using the provided configuration and a login hint. +/// Starts an interactive sign-in flow on macOS using the provided hint. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - hint:(nullable NSString *)hint - completion:(nullable GIDSignInCompletion)completion; +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + completion:(nullable GIDSignInCompletion)completion; -/// Starts an interactive sign-in flow on macOS using the provided configuration and a login hint. +/// Starts an interactive sign-in flow on macOS using the provided hint. /// /// The completion will be called at the end of this process. Any saved sign-in state will be /// replaced by the result of this flow. Note that this method should not be called when the app is /// starting up, (e.g in `application:didFinishLaunchingWithOptions:`); instead use the /// `restorePreviousSignInWithCompletion:` method to restore a previous sign-in. /// -/// @param configuration The configuration properties to be used for this flow. /// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. /// @param hint An optional hint for the authorization server, for example the user's ID or email /// address, to be prefilled if possible. @@ -232,11 +224,10 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); /// @param completion The `GIDSignInCompletion` block that is called on completion. This block will /// be called asynchronously on the main queue. -- (void)signInWithConfiguration:(GIDConfiguration *)configuration - presentingWindow:(NSWindow *)presentingWindow - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable GIDSignInCompletion)completion; +- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow + hint:(nullable NSString *)hint + additionalScopes:(nullable NSArray *)additionalScopes + completion:(nullable GIDSignInCompletion)completion; /// Starts an interactive consent flow on macOS to add scopes to the current user's grants. /// diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 0a74e01c..7de36a43 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -342,7 +342,7 @@ - (void)setUp { forKey:kAppHasRunBeforeKey]; _signIn = [[GIDSignIn alloc] initPrivate]; - _configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; + _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; _hint = nil; __weak GIDSignInTest *weakSelf = self; @@ -607,10 +607,10 @@ - (void)testAddScopes { } - (void)testOpenIDRealm { - _configuration = [[GIDConfiguration alloc] initWithClientID:kClientId - serverClientID:nil - hostedDomain:nil - openIDRealm:kOpenIDRealm]; + _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId + serverClientID:nil + hostedDomain:nil + openIDRealm:kOpenIDRealm]; [self OAuthLoginWithAddScopesFlow:NO authError:nil @@ -642,10 +642,10 @@ - (void)testOAuthLogin_LoginHint { } - (void)testOAuthLogin_HostedDomain { - _configuration = [[GIDConfiguration alloc] initWithClientID:kClientId - serverClientID:nil - hostedDomain:kHostedDomain - openIDRealm:nil]; + _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId + serverClientID:nil + hostedDomain:kHostedDomain + openIDRealm:nil]; [self OAuthLoginWithAddScopesFlow:NO authError:nil @@ -880,30 +880,28 @@ - (void)testPresentingViewControllerException { #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - XCTAssertThrows([_signIn signInWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:_presentingViewController + XCTAssertThrows([_signIn signInWithPresentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:_presentingWindow + XCTAssertThrows([_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - hint:_hint - completion:_completion]); + hint:_hint + completion:_completion]); } - (void)testClientIDMissingException { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" - GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; + _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop BOOL threw = NO; @try { - [_signIn signInWithConfiguration:configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:_presentingViewController + [_signIn signInWithPresentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:_presentingWindow + [_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - completion:nil]; + completion:nil]; } @catch (NSException *exception) { threw = YES; XCTAssertEqualObjects(exception.description, @@ -917,14 +915,13 @@ - (void)testSchemesNotSupportedException { [_fakeMainBundle fakeMissingAllSchemes]; BOOL threw = NO; @try { - [_signIn signInWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:_presentingViewController + [_signIn signInWithPresentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:_presentingWindow + [_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - hint:_hint - completion:_completion]; + hint:_hint + completion:_completion]; } @catch (NSException *exception) { threw = YES; XCTAssertEqualObjects(exception.description, @@ -1239,24 +1236,22 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow completion:completion]; } else { if (useAdditionalScopes) { - [_signIn signInWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:_presentingViewController + [_signIn signInWithPresentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:_presentingWindow + [_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - hint:_hint - additionalScopes:additionalScopes - completion:completion]; + hint:_hint + additionalScopes:additionalScopes + completion:completion]; } else { - [_signIn signInWithConfiguration:_configuration #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:_presentingViewController + [_signIn signInWithPresentingViewController:_presentingViewController #elif TARGET_OS_OSX - presentingWindow:_presentingWindow + [_signIn signInWithPresentingWindow:_presentingWindow #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - hint:_hint - completion:completion]; + hint:_hint + completion:completion]; } } diff --git a/Samples/ObjC/SignInSample/SignInSample-Info.plist b/Samples/ObjC/SignInSample/SignInSample-Info.plist index 1667ac1c..428b1583 100644 --- a/Samples/ObjC/SignInSample/SignInSample-Info.plist +++ b/Samples/ObjC/SignInSample/SignInSample-Info.plist @@ -67,5 +67,8 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + + GIDClientID + 589453917038-qaoga89fitj2ukrsq27ko56fimmojac6.apps.googleusercontent.com diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index 5f422f6a..5b3f1651 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -37,11 +37,6 @@ // Accessibility Identifiers. static NSString *const kCredentialsButtonAccessibilityIdentifier = @"Credentials"; -// DO NOT USE THIS CLIENT ID. IT WILL NOT WORK FOR YOUR APP. -// Please use the client ID created for you by Google. -static NSString * const kClientID = - @"589453917038-qaoga89fitj2ukrsq27ko56fimmojac6.apps.googleusercontent.com"; - @implementation SignInViewController { // This is an array of arrays, each one corresponding to the cell // labels for its respective section. @@ -58,9 +53,6 @@ @implementation SignInViewController { // Map that keeps track of which cell corresponds to which DataPickerState. NSDictionary *_drilldownCellState; - - // Configuration options for GIDSignIn. - GIDConfiguration *_configuration; } #pragma mark - View lifecycle @@ -97,8 +89,6 @@ - (void)setUp { // Make sure the GIDSignInButton class is linked in because references from // xib file doesn't count. [GIDSignInButton class]; - - _configuration = [[GIDConfiguration alloc] initWithClientID:kClientID]; } - (id)initWithNibName:(NSString *)nibNameOrNil @@ -257,9 +247,9 @@ - (void)updateButtons { #pragma mark - IBActions - (IBAction)signIn:(id)sender { - [GIDSignIn.sharedInstance signInWithConfiguration:_configuration - presentingViewController:self - completion:^(GIDGoogleUser *user, NSError *error) { + [GIDSignIn.sharedInstance signInWithPresentingViewController:self + completion:^(GIDGoogleUser *user, + NSError *error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Authentication error: %@", error]; diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj index 329cad53..2fefe6ab 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj @@ -553,8 +553,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -564,6 +566,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -574,8 +577,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -585,6 +590,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -652,10 +658,12 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_ENTITLEMENTS = macOS/DaysUntilBirthdayOnMac.entitlements; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"macOS/Preview Content\""; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = macOS/Info.plist; @@ -668,6 +676,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = Google.DaysUntilBirthdayOnMac; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development macOS"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -681,10 +690,11 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_ENTITLEMENTS = macOS/DaysUntilBirthdayOnMac.entitlements; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"macOS/Preview Content\""; + DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = macOS/Info.plist; @@ -697,6 +707,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = Google.DaysUntilBirthdayOnMac; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development macOS"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 2a0e88fd..499733a0 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -19,18 +19,7 @@ import GoogleSignIn /// An observable class for authenticating via Google. final class GoogleSignInAuthenticator: ObservableObject { - // TODO: Replace this with your own ID. - #if os(iOS) - private let clientID = "687389107077-8qr6dh8fr4uaja89sdr5ieqb7mep04qv.apps.googleusercontent.com" - #elseif os(macOS) - private let clientID = "687389107077-8qr6dh8fr4uaja89sdr5ieqb7mep04qv.apps.googleusercontent.com" - #endif - - private lazy var configuration: GIDConfiguration = { - return GIDConfiguration(clientID: clientID) - }() - - private var authViewModel: AuthenticationViewModel + private var authViewModel: AuthenticationViewModel /// Creates an instance of this authenticator. /// - parameter authViewModel: The view model this authenticator will set logged in status on. @@ -47,8 +36,7 @@ final class GoogleSignInAuthenticator: ObservableObject { return } - GIDSignIn.sharedInstance.signIn(with: configuration, - presenting: rootViewController) { user, error in + GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { user, error in guard let user = user else { print("Error! \(String(describing: error))") return @@ -62,8 +50,7 @@ final class GoogleSignInAuthenticator: ObservableObject { return } - GIDSignIn.sharedInstance.signIn(with: configuration, - presenting: presentingWindow) { user, error in + GIDSignIn.sharedInstance.signIn(withPresenting: presentingWindow) { user, error in guard let user = user else { print("Error! \(String(describing: error))") return diff --git a/Samples/Swift/DaysUntilBirthday/iOS/Info.plist b/Samples/Swift/DaysUntilBirthday/iOS/Info.plist index 6d7f2245..b6f271b2 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/Info.plist +++ b/Samples/Swift/DaysUntilBirthday/iOS/Info.plist @@ -61,5 +61,8 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + + GIDClientID + 687389107077-8qr6dh8fr4uaja89sdr5ieqb7mep04qv.apps.googleusercontent.com diff --git a/Samples/Swift/DaysUntilBirthday/macOS/Info.plist b/Samples/Swift/DaysUntilBirthday/macOS/Info.plist index 50328877..92ac30c8 100644 --- a/Samples/Swift/DaysUntilBirthday/macOS/Info.plist +++ b/Samples/Swift/DaysUntilBirthday/macOS/Info.plist @@ -15,5 +15,8 @@ + + GIDClientID + 687389107077-8qr6dh8fr4uaja89sdr5ieqb7mep04qv.apps.googleusercontent.com From 1d58a2d9a2fc2ba0f06a2a6f2625129f164e32ce Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Fri, 23 Sep 2022 15:33:39 -0700 Subject: [PATCH 02/10] Use -objectForInfoDictionaryKey: instead of infoDictionary subscripting. --- GoogleSignIn/Sources/GIDSignIn.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 490cc396..1b064063 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -475,17 +475,17 @@ + (GIDSignIn *)sharedInstance { - (id)initPrivate { self = [super init]; if (self) { - // Get the Info.plist dictionary from the app's main bundle. - NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + // Get the app's main bundle. + NSBundle *bundle = [NSBundle mainBundle]; - NSString *clientID = infoDictionary[kConfigClientIDKey]; - NSString *serverClientID = infoDictionary[kConfigServerClientIDKey]; - NSString *hostedDomain = infoDictionary[kConfigHostedDomainKey]; - NSString *openIDRealm = infoDictionary[kConfigOpenIDRealmKey]; + // Retrieve any config parameters from the main bundle. + NSString *clientID = [bundle objectForInfoDictionaryKey:kConfigClientIDKey]; + NSString *serverClientID = [bundle objectForInfoDictionaryKey:kConfigServerClientIDKey]; + NSString *hostedDomain = [bundle objectForInfoDictionaryKey:kConfigHostedDomainKey]; + NSString *openIDRealm = [bundle objectForInfoDictionaryKey:kConfigOpenIDRealmKey]; + // Try to construct an initial configuration, we need at least a client ID. GIDConfiguration *configuration; - - // We need at least a client ID to create a configuration. if (clientID) { configuration = [[GIDConfiguration alloc] initWithClientID:clientID serverClientID:serverClientID From 8aa0d393ece2f2221ed4c7ae56bc7a22acb4a3af Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Mon, 26 Sep 2022 16:21:08 -0700 Subject: [PATCH 03/10] Add tests for basic config scenarios. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 9 ++++ GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 54 ++++++++++++++++----- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 33 ++++++++++++- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index c8095450..28f08e95 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -80,4 +80,13 @@ */ - (void)fakeOtherSchemesAndAllSchemes; +/** + * @fn fakeWithClientID:serverClientID:hostedDomain:openIDRealm: + * @brief Sets values for faked Info.plist params. + */ +- (void)fakeWithClientID:(NSString *)clientID + serverClientID:(NSString *)serverClientID + hostedDomain:(NSString *)hostedDomain + openIDRealm:(NSString *)openIDRealm; + @end diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index 812b7252..a3d08ad2 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -21,9 +21,22 @@ static NSString *const kCFBundleURLSchemesKey = @"CFBundleURLSchemes"; +// Info.plist config keys +static NSString *const kConfigClientIDKey = @"GIDClientID"; +static NSString *const kConfigServerClientIDKey = @"GIDServerClientID"; +static NSString *const kConfigHostedDomainKey = @"GIDHostedDomain"; +static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm"; + @implementation GIDFakeMainBundle { // Represents the CFBundleURLTypes of the mocked app bundle's info.plist. __block NSArray *_fakeSupportedSchemes; + + // Represents the Info.plist keys to fake. + NSArray *_fakedKeys; + + // Represents the values for any Info.plist keys to be faked. + NSMutableDictionary *_fakeConfig; + NSString *_clientId; NSString *_bundleId; @@ -33,12 +46,20 @@ - (void)startFakingWithBundleId:(NSString *)bundleId clientId:(NSString *)client _bundleId = bundleId; _clientId = clientId; + _fakedKeys = @[ kCFBundleURLTypesKey, + kConfigClientIDKey, + kConfigServerClientIDKey, + kConfigHostedDomainKey, + kConfigOpenIDRealmKey ]; + + _fakeConfig = [@{ @"GIDClientID" : clientId } mutableCopy]; + [GULSwizzler swizzleClass:[NSBundle class] selector:@selector(objectForInfoDictionaryKey:) isClassSelector:NO - withBlock:^(id _self, NSString *key) { - if ([key isEqual:kCFBundleURLTypesKey]) { - return self->_fakeSupportedSchemes; + withBlock:^id(id _self, NSString *key) { + if ([self->_fakedKeys containsObject:key]) { + return self->_fakeConfig[key]; } else { @throw [NSException exceptionWithName:@"Requested unexpected info.plist key." reason:nil @@ -51,7 +72,7 @@ - (void)stopFaking { [GULSwizzler unswizzleClass:[NSBundle class] selector:@selector(objectForInfoDictionaryKey:) isClassSelector:NO]; - _fakeSupportedSchemes = nil; + _fakeConfig = nil; } #pragma mark - Utilities @@ -93,7 +114,7 @@ - (NSString *)stringByFlippingCasesInString:(NSString *)original { #pragma mark - URL Schemes - (void)fakeAllSchemesSupported { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ _bundleId ] }, @@ -104,7 +125,7 @@ - (void)fakeAllSchemesSupported { } - (void)fakeAllSchemesSupportedAndMerged { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ _bundleId, @@ -119,7 +140,7 @@ - (void)fakeAllSchemesSupportedWithCasesMangled { [self stringByFlippingCasesInString:_bundleId]; NSString *caseFlippedReverseClientId = [self stringByFlippingCasesInString:[self reversedClientId]]; - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ caseFlippedBundleId ] }, @@ -130,7 +151,7 @@ - (void)fakeAllSchemesSupportedWithCasesMangled { } - (void)fakeMissingClientIdScheme { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ _bundleId ] } @@ -138,11 +159,11 @@ - (void)fakeMissingClientIdScheme { } - (void)fakeMissingAllSchemes { - _fakeSupportedSchemes = nil; + _fakeConfig[kCFBundleURLTypesKey] = nil; } - (void)fakeOtherSchemes { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ @"junk" ] } @@ -150,7 +171,7 @@ - (void)fakeOtherSchemes { } - (void)fakeOtherSchemesAndAllSchemes { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ _bundleId ] }, @@ -163,4 +184,15 @@ - (void)fakeOtherSchemesAndAllSchemes { ]; } +- (void)fakeWithClientID:(NSString *)clientID + serverClientID:(NSString *)serverClientID + hostedDomain:(NSString *)hostedDomain + openIDRealm:(NSString *)openIDRealm { + _clientId = clientID; + _fakeConfig[kConfigClientIDKey] = clientID; + _fakeConfig[kConfigServerClientIDKey] = serverClientID; + _fakeConfig[kConfigHostedDomainKey] = hostedDomain; + _fakeConfig[kConfigOpenIDRealmKey] = openIDRealm; +} + @end diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 7de36a43..c1c94d74 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -85,6 +85,7 @@ static NSString * const kClientId = @"FakeClientID"; static NSString * const kDotReversedClientId = @"FakeClientID"; static NSString * const kClientId2 = @"FakeClientID2"; +static NSString * const kServerClientId = @"FakeServerClientID"; static NSString * const kAppBundleId = @"FakeBundleID"; static NSString * const kLanguage = @"FakeLanguage"; static NSString * const kScope = @"FakeScope"; @@ -342,7 +343,6 @@ - (void)setUp { forKey:kAppHasRunBeforeKey]; _signIn = [[GIDSignIn alloc] initPrivate]; - _signIn.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; _hint = nil; __weak GIDSignInTest *weakSelf = self; @@ -394,6 +394,37 @@ - (void)testShareInstance { XCTAssertTrue(signIn1 == signIn2, @"shared instance must be singleton"); } +- (void)testInitPrivate { + GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; + XCTAssertNotNil(signIn.configuration); + XCTAssertEqual(signIn.configuration.clientID, kClientId); + XCTAssertNil(signIn.configuration.serverClientID); + XCTAssertNil(signIn.configuration.hostedDomain); + XCTAssertNil(signIn.configuration.openIDRealm); +} + +- (void)testInitPrivate_noConfig { + [_fakeMainBundle fakeWithClientID:nil + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; + XCTAssertNil(signIn.configuration); +} + +- (void)testInitPrivate_fullConfig { + [_fakeMainBundle fakeWithClientID:kClientId + serverClientID:kServerClientId + hostedDomain:kFakeHostedDomain + openIDRealm:kOpenIDRealm]; + GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; + XCTAssertNotNil(signIn.configuration); + XCTAssertEqual(signIn.configuration.clientID, kClientId); + XCTAssertEqual(signIn.configuration.serverClientID, kServerClientId); + XCTAssertEqual(signIn.configuration.hostedDomain, kFakeHostedDomain); + XCTAssertEqual(signIn.configuration.openIDRealm, kOpenIDRealm); +} + - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { [[[_authorization expect] andReturn:_authState] authState]; OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse); From 2189b3962620808cd0dfa88518e82b55f5a16578 Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Tue, 27 Sep 2022 11:39:17 -0700 Subject: [PATCH 04/10] Handle invalid config scenario. --- GoogleSignIn/Sources/GIDSignIn.m | 29 +++++++++++++++++---- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 8 +++--- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 19 +++++--------- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 9 +++++++ 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 1b064063..eeb3c076 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -479,12 +479,31 @@ - (id)initPrivate { NSBundle *bundle = [NSBundle mainBundle]; // Retrieve any config parameters from the main bundle. - NSString *clientID = [bundle objectForInfoDictionaryKey:kConfigClientIDKey]; - NSString *serverClientID = [bundle objectForInfoDictionaryKey:kConfigServerClientIDKey]; - NSString *hostedDomain = [bundle objectForInfoDictionaryKey:kConfigHostedDomainKey]; - NSString *openIDRealm = [bundle objectForInfoDictionaryKey:kConfigOpenIDRealmKey]; + NSString *clientID; + id configClientID = [bundle objectForInfoDictionaryKey:kConfigClientIDKey]; + if ([configClientID isKindOfClass:[NSString class]]) { + clientID = configClientID; + } + + NSString *serverClientID; + id configServerClientID = [bundle objectForInfoDictionaryKey:kConfigServerClientIDKey]; + if ([configServerClientID isKindOfClass:[NSString class]]) { + serverClientID = configServerClientID; + } + + NSString *hostedDomain; + id configHostedDomain = [bundle objectForInfoDictionaryKey:kConfigHostedDomainKey]; + if ([configHostedDomain isKindOfClass:[NSString class]]) { + hostedDomain = configHostedDomain; + } + + NSString *openIDRealm; + id configopenIDRealm = [bundle objectForInfoDictionaryKey:kConfigOpenIDRealmKey]; + if ([configopenIDRealm isKindOfClass:[NSString class]]) { + openIDRealm = configopenIDRealm; + } - // Try to construct an initial configuration, we need at least a client ID. + // Try to construct an initial configuration. We need at least a client ID. GIDConfiguration *configuration; if (clientID) { configuration = [[GIDConfiguration alloc] initWithClientID:clientID diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 28f08e95..f31f5ff2 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -84,9 +84,9 @@ * @fn fakeWithClientID:serverClientID:hostedDomain:openIDRealm: * @brief Sets values for faked Info.plist params. */ -- (void)fakeWithClientID:(NSString *)clientID - serverClientID:(NSString *)serverClientID - hostedDomain:(NSString *)hostedDomain - openIDRealm:(NSString *)openIDRealm; +- (void)fakeWithClientID:(id)clientID + serverClientID:(id)serverClientID + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm; @end diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index a3d08ad2..6750eeb6 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -28,18 +28,14 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm"; @implementation GIDFakeMainBundle { - // Represents the CFBundleURLTypes of the mocked app bundle's info.plist. - __block NSArray *_fakeSupportedSchemes; - + NSString *_clientId; + NSString *_bundleId; + // Represents the Info.plist keys to fake. NSArray *_fakedKeys; // Represents the values for any Info.plist keys to be faked. NSMutableDictionary *_fakeConfig; - - - NSString *_clientId; - NSString *_bundleId; } - (void)startFakingWithBundleId:(NSString *)bundleId clientId:(NSString *)clientId { @@ -184,11 +180,10 @@ - (void)fakeOtherSchemesAndAllSchemes { ]; } -- (void)fakeWithClientID:(NSString *)clientID - serverClientID:(NSString *)serverClientID - hostedDomain:(NSString *)hostedDomain - openIDRealm:(NSString *)openIDRealm { - _clientId = clientID; +- (void)fakeWithClientID:(id)clientID + serverClientID:(id)serverClientID + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm { _fakeConfig[kConfigClientIDKey] = clientID; _fakeConfig[kConfigServerClientIDKey] = serverClientID; _fakeConfig[kConfigHostedDomainKey] = hostedDomain; diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index c1c94d74..bdabbe35 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -425,6 +425,15 @@ - (void)testInitPrivate_fullConfig { XCTAssertEqual(signIn.configuration.openIDRealm, kOpenIDRealm); } +- (void)testInitPrivate_invalidConfig { + [_fakeMainBundle fakeWithClientID:@[ @"bad", @"config", @"values" ] + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; + XCTAssertNil(signIn.configuration); +} + - (void)testRestorePreviousSignInNoRefresh_hasPreviousUser { [[[_authorization expect] andReturn:_authState] authState]; OCMStub([_authState lastTokenResponse]).andReturn(_tokenResponse); From 83ca781bde9614ae05ec8d9bf18ee5cd9bed97bd Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Tue, 27 Sep 2022 11:49:56 -0700 Subject: [PATCH 05/10] Remove bundle ID URL scheme support from our fake bundle. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 3 +-- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 22 ++----------------- .../Tests/Unit/GIDSignInCallbackSchemesTest.m | 3 +-- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 3 +-- 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index f31f5ff2..9f9766a0 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -25,10 +25,9 @@ /** * @fn startFakingWithBundleId:clientId: * @brief Starts faking [NSBundle mainBundle] - * @param bundleId The fake bundle idenfitier for the app. * @param clientId The fake client idenfitier for the app. */ -- (void)startFakingWithBundleId:(NSString *)bundleId clientId:(NSString *)clientId; +- (void)startFakingWithClientId:(NSString *)clientId; /** * @fn stopFaking diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index 6750eeb6..4fcbfa91 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -29,7 +29,6 @@ @implementation GIDFakeMainBundle { NSString *_clientId; - NSString *_bundleId; // Represents the Info.plist keys to fake. NSArray *_fakedKeys; @@ -38,8 +37,7 @@ @implementation GIDFakeMainBundle { NSMutableDictionary *_fakeConfig; } -- (void)startFakingWithBundleId:(NSString *)bundleId clientId:(NSString *)clientId { - _bundleId = bundleId; +- (void)startFakingWithClientId:(NSString *)clientId { _clientId = clientId; _fakedKeys = @[ kCFBundleURLTypesKey, @@ -111,9 +109,6 @@ - (NSString *)stringByFlippingCasesInString:(NSString *)original { - (void)fakeAllSchemesSupported { _fakeConfig[kCFBundleURLTypesKey] = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - }, @{ kCFBundleURLSchemesKey : @[ [self reversedClientId] ] } @@ -124,7 +119,6 @@ - (void)fakeAllSchemesSupportedAndMerged { _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ - _bundleId, [self reversedClientId] ] }, @@ -132,14 +126,9 @@ - (void)fakeAllSchemesSupportedAndMerged { } - (void)fakeAllSchemesSupportedWithCasesMangled { - NSString *caseFlippedBundleId = - [self stringByFlippingCasesInString:_bundleId]; NSString *caseFlippedReverseClientId = [self stringByFlippingCasesInString:[self reversedClientId]]; _fakeConfig[kCFBundleURLTypesKey] = @[ - @{ - kCFBundleURLSchemesKey : @[ caseFlippedBundleId ] - }, @{ kCFBundleURLSchemesKey : @[ caseFlippedReverseClientId ] } @@ -147,11 +136,7 @@ - (void)fakeAllSchemesSupportedWithCasesMangled { } - (void)fakeMissingClientIdScheme { - _fakeConfig[kCFBundleURLTypesKey] = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - } - ]; + [self fakeMissingAllSchemes]; } - (void)fakeMissingAllSchemes { @@ -168,9 +153,6 @@ - (void)fakeOtherSchemes { - (void)fakeOtherSchemesAndAllSchemes { _fakeConfig[kCFBundleURLTypesKey] = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - }, @{ kCFBundleURLSchemesKey : @[ @"junk" ] }, diff --git a/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m b/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m index 67e0da61..c9419fa9 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m @@ -18,7 +18,6 @@ #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" static NSString *const kClientId = @"FakeClientID"; -static NSString *const kBundleId = @"FakeBundleID"; @interface GIDSignInCallbackSchemesTest : XCTestCase @end @@ -29,7 +28,7 @@ @implementation GIDSignInCallbackSchemesTest { - (void)setUp { _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; - [_fakeMainBundle startFakingWithBundleId:kBundleId clientId:kClientId]; + [_fakeMainBundle startFakingWithClientId:kClientId]; } - (void)tearDown { diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index bdabbe35..41394e51 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -86,7 +86,6 @@ static NSString * const kDotReversedClientId = @"FakeClientID"; static NSString * const kClientId2 = @"FakeClientID2"; static NSString * const kServerClientId = @"FakeServerClientID"; -static NSString * const kAppBundleId = @"FakeBundleID"; static NSString * const kLanguage = @"FakeLanguage"; static NSString * const kScope = @"FakeScope"; static NSString * const kScope2 = @"FakeScope2"; @@ -335,7 +334,7 @@ - (void)setUp { // Fakes _fetcherService = [[GIDFakeFetcherService alloc] init]; _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; - [_fakeMainBundle startFakingWithBundleId:kAppBundleId clientId:kClientId]; + [_fakeMainBundle startFakingWithClientId:kClientId]; [_fakeMainBundle fakeAllSchemesSupported]; // Object under test From 77b76e34d83d8d4915e9b095014d2b1264bbdd44 Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Tue, 27 Sep 2022 11:53:03 -0700 Subject: [PATCH 06/10] Fix indentation. --- .../Shared/Services/GoogleSignInAuthenticator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 499733a0..00c144b7 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -19,7 +19,7 @@ import GoogleSignIn /// An observable class for authenticating via Google. final class GoogleSignInAuthenticator: ObservableObject { - private var authViewModel: AuthenticationViewModel + private var authViewModel: AuthenticationViewModel /// Creates an instance of this authenticator. /// - parameter authViewModel: The view model this authenticator will set logged in status on. From 8b9435b79bf02a6408c5e63acb60cbd192c1bf40 Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Tue, 27 Sep 2022 11:59:53 -0700 Subject: [PATCH 07/10] Update doc comments. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 9f9766a0..7cca8c47 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -23,7 +23,7 @@ @interface GIDFakeMainBundle : NSObject /** - * @fn startFakingWithBundleId:clientId: + * @fn startFakingWithClientId: * @brief Starts faking [NSBundle mainBundle] * @param clientId The fake client idenfitier for the app. */ @@ -82,6 +82,10 @@ /** * @fn fakeWithClientID:serverClientID:hostedDomain:openIDRealm: * @brief Sets values for faked Info.plist params. + * @param clientId The fake client idenfitier for the app. + * @param serverClientId The fake server client idenfitier for the app. + * @param hostedDomain The fake hosted domain for the app. + * @param openIDRealm The fake OpenID realm for the app. */ - (void)fakeWithClientID:(id)clientID serverClientID:(id)serverClientID From 112f1766f161699672df47187fd4336386a0b7ea Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Tue, 27 Sep 2022 12:21:12 -0700 Subject: [PATCH 08/10] Update method names and doc comments. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 10 +++++----- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 2 +- GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m | 2 +- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 7cca8c47..3086880e 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -23,11 +23,11 @@ @interface GIDFakeMainBundle : NSObject /** - * @fn startFakingWithClientId: + * @fn startFakingWithClientID: * @brief Starts faking [NSBundle mainBundle] - * @param clientId The fake client idenfitier for the app. + * @param clientID The fake client idenfitier for the app. */ -- (void)startFakingWithClientId:(NSString *)clientId; +- (void)startFakingWithClientID:(NSString *)clientID; /** * @fn stopFaking @@ -82,8 +82,8 @@ /** * @fn fakeWithClientID:serverClientID:hostedDomain:openIDRealm: * @brief Sets values for faked Info.plist params. - * @param clientId The fake client idenfitier for the app. - * @param serverClientId The fake server client idenfitier for the app. + * @param clientID The fake client idenfitier for the app. + * @param serverClientID The fake server client idenfitier for the app. * @param hostedDomain The fake hosted domain for the app. * @param openIDRealm The fake OpenID realm for the app. */ diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index 4fcbfa91..d017e60c 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -37,7 +37,7 @@ @implementation GIDFakeMainBundle { NSMutableDictionary *_fakeConfig; } -- (void)startFakingWithClientId:(NSString *)clientId { +- (void)startFakingWithClientID:(NSString *)clientId { _clientId = clientId; _fakedKeys = @[ kCFBundleURLTypesKey, diff --git a/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m b/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m index c9419fa9..c34536a5 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m @@ -28,7 +28,7 @@ @implementation GIDSignInCallbackSchemesTest { - (void)setUp { _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; - [_fakeMainBundle startFakingWithClientId:kClientId]; + [_fakeMainBundle startFakingWithClientID:kClientId]; } - (void)tearDown { diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 41394e51..61f18f41 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -334,7 +334,7 @@ - (void)setUp { // Fakes _fetcherService = [[GIDFakeFetcherService alloc] init]; _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; - [_fakeMainBundle startFakingWithClientId:kClientId]; + [_fakeMainBundle startFakingWithClientID:kClientId]; [_fakeMainBundle fakeAllSchemesSupported]; // Object under test From 0b2212b22d66bb37308a7c5a7951a7d271e0f897 Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Wed, 28 Sep 2022 13:32:37 -0700 Subject: [PATCH 09/10] Simplify setting the initial config. --- GoogleSignIn/Sources/GIDSignIn.m | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index eeb3c076..01c54009 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -503,15 +503,13 @@ - (id)initPrivate { openIDRealm = configopenIDRealm; } - // Try to construct an initial configuration. We need at least a client ID. - GIDConfiguration *configuration; + // If we have at least a client ID, try to construct an initial configuration. if (clientID) { - configuration = [[GIDConfiguration alloc] initWithClientID:clientID - serverClientID:serverClientID - hostedDomain:hostedDomain - openIDRealm:openIDRealm]; // Set the initial active configuation - _configuration = configuration; + _configuration = [[GIDConfiguration alloc] initWithClientID:clientID + serverClientID:serverClientID + hostedDomain:hostedDomain + openIDRealm:openIDRealm]; } // Check to see if the 3P app is being run for the first time after a fresh install. From 99d0e5bfd5f1df51e00912ecb5861a9f372f4a3c Mon Sep 17 00:00:00 2001 From: Peter Andrews Date: Wed, 28 Sep 2022 16:09:41 -0700 Subject: [PATCH 10/10] Dry up Info.plist config loading. --- GoogleSignIn/Sources/GIDSignIn.m | 76 +++++++++++++++++--------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 01c54009..86de6504 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -475,41 +475,12 @@ + (GIDSignIn *)sharedInstance { - (id)initPrivate { self = [super init]; if (self) { - // Get the app's main bundle. - NSBundle *bundle = [NSBundle mainBundle]; - - // Retrieve any config parameters from the main bundle. - NSString *clientID; - id configClientID = [bundle objectForInfoDictionaryKey:kConfigClientIDKey]; - if ([configClientID isKindOfClass:[NSString class]]) { - clientID = configClientID; - } - - NSString *serverClientID; - id configServerClientID = [bundle objectForInfoDictionaryKey:kConfigServerClientIDKey]; - if ([configServerClientID isKindOfClass:[NSString class]]) { - serverClientID = configServerClientID; - } - - NSString *hostedDomain; - id configHostedDomain = [bundle objectForInfoDictionaryKey:kConfigHostedDomainKey]; - if ([configHostedDomain isKindOfClass:[NSString class]]) { - hostedDomain = configHostedDomain; - } + // Get the bundle of the current executable. + NSBundle *bundle = NSBundle.mainBundle; - NSString *openIDRealm; - id configopenIDRealm = [bundle objectForInfoDictionaryKey:kConfigOpenIDRealmKey]; - if ([configopenIDRealm isKindOfClass:[NSString class]]) { - openIDRealm = configopenIDRealm; - } - - // If we have at least a client ID, try to construct an initial configuration. - if (clientID) { - // Set the initial active configuation - _configuration = [[GIDConfiguration alloc] initWithClientID:clientID - serverClientID:serverClientID - hostedDomain:hostedDomain - openIDRealm:openIDRealm]; + // If we have a bundle, try to set the active configuration from the bundle's Info.plist. + if (bundle) { + _configuration = [GIDSignIn configurationFromBundle:bundle]; } // Check to see if the 3P app is being run for the first time after a fresh install. @@ -1005,10 +976,11 @@ - (void)assertValidParameters { // Assert that the presenting view controller has been set. - (void)assertValidPresentingViewController { #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - if (!_currentOptions.presentingViewController) { + if (!_currentOptions.presentingViewController) #elif TARGET_OS_OSX - if (!_currentOptions.presentingWindow) { + if (!_currentOptions.presentingWindow) #endif // TARGET_OS_OSX + { // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) [NSException raise:NSInvalidArgumentException format:@"|presentingViewController| must be set."]; @@ -1070,6 +1042,38 @@ - (void)setCurrentUserWithKVO:(GIDGoogleUser *_Nullable)user { [self didChangeValueForKey:NSStringFromSelector(@selector(currentUser))]; } +// Try to retrieve a configuration value from an |NSBundle|'s Info.plist for a given key. ++ (nullable NSString *)configValueFromBundle:(NSBundle *)bundle forKey:(NSString *)key { + NSString *value; + id configValue = [bundle objectForInfoDictionaryKey:key]; + if ([configValue isKindOfClass:[NSString class]]) { + value = configValue; + } + return value; +} + +// Try to generate a |GIDConfiguration| from an |NSBundle|'s Info.plist. ++ (nullable GIDConfiguration *)configurationFromBundle:(NSBundle *)bundle { + GIDConfiguration *configuration; + + // Retrieve any valid config parameters from the bundle's Info.plist. + NSString *clientID = [GIDSignIn configValueFromBundle:bundle forKey:kConfigClientIDKey]; + NSString *serverClientID = [GIDSignIn configValueFromBundle:bundle + forKey:kConfigServerClientIDKey]; + NSString *hostedDomain = [GIDSignIn configValueFromBundle:bundle forKey:kConfigHostedDomainKey]; + NSString *openIDRealm = [GIDSignIn configValueFromBundle:bundle forKey:kConfigOpenIDRealmKey]; + + // If we have at least a client ID, try to construct a configuration. + if (clientID) { + configuration = [[GIDConfiguration alloc] initWithClientID:clientID + serverClientID:serverClientID + hostedDomain:hostedDomain + openIDRealm:openIDRealm]; + } + + return configuration; +} + @end NS_ASSUME_NONNULL_END