diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 8cfc3d60..86de6504 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,14 @@ + (GIDSignIn *)sharedInstance { - (id)initPrivate { self = [super init]; if (self) { + // Get the bundle of the current executable. + NSBundle *bundle = NSBundle.mainBundle; + + // 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. BOOL isFreshInstall = [self isFreshInstall]; @@ -514,6 +520,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]; @@ -962,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."]; @@ -1027,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 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/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index c8095450..3086880e 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -23,12 +23,11 @@ @interface GIDFakeMainBundle : NSObject /** - * @fn startFakingWithBundleId:clientId: + * @fn startFakingWithClientID: * @brief Starts faking [NSBundle mainBundle] - * @param bundleId The fake bundle idenfitier for the app. - * @param clientId The fake client 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 @@ -80,4 +79,17 @@ */ - (void)fakeOtherSchemesAndAllSchemes; +/** + * @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 + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm; + @end diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index 812b7252..d017e60c 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -21,24 +21,39 @@ static NSString *const kCFBundleURLSchemesKey = @"CFBundleURLSchemes"; -@implementation GIDFakeMainBundle { - // Represents the CFBundleURLTypes of the mocked app bundle's info.plist. - __block NSArray *_fakeSupportedSchemes; +// 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 { 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; } -- (void)startFakingWithBundleId:(NSString *)bundleId clientId:(NSString *)clientId { - _bundleId = bundleId; +- (void)startFakingWithClientID:(NSString *)clientId { _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 +66,7 @@ - (void)stopFaking { [GULSwizzler unswizzleClass:[NSBundle class] selector:@selector(objectForInfoDictionaryKey:) isClassSelector:NO]; - _fakeSupportedSchemes = nil; + _fakeConfig = nil; } #pragma mark - Utilities @@ -93,10 +108,7 @@ - (NSString *)stringByFlippingCasesInString:(NSString *)original { #pragma mark - URL Schemes - (void)fakeAllSchemesSupported { - _fakeSupportedSchemes = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - }, + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ [self reversedClientId] ] } @@ -104,10 +116,9 @@ - (void)fakeAllSchemesSupported { } - (void)fakeAllSchemesSupportedAndMerged { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ - _bundleId, [self reversedClientId] ] }, @@ -115,14 +126,9 @@ - (void)fakeAllSchemesSupportedAndMerged { } - (void)fakeAllSchemesSupportedWithCasesMangled { - NSString *caseFlippedBundleId = - [self stringByFlippingCasesInString:_bundleId]; NSString *caseFlippedReverseClientId = [self stringByFlippingCasesInString:[self reversedClientId]]; - _fakeSupportedSchemes = @[ - @{ - kCFBundleURLSchemesKey : @[ caseFlippedBundleId ] - }, + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ caseFlippedReverseClientId ] } @@ -130,19 +136,15 @@ - (void)fakeAllSchemesSupportedWithCasesMangled { } - (void)fakeMissingClientIdScheme { - _fakeSupportedSchemes = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - } - ]; + [self fakeMissingAllSchemes]; } - (void)fakeMissingAllSchemes { - _fakeSupportedSchemes = nil; + _fakeConfig[kCFBundleURLTypesKey] = nil; } - (void)fakeOtherSchemes { - _fakeSupportedSchemes = @[ + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ @"junk" ] } @@ -150,10 +152,7 @@ - (void)fakeOtherSchemes { } - (void)fakeOtherSchemesAndAllSchemes { - _fakeSupportedSchemes = @[ - @{ - kCFBundleURLSchemesKey : @[ _bundleId ] - }, + _fakeConfig[kCFBundleURLTypesKey] = @[ @{ kCFBundleURLSchemesKey : @[ @"junk" ] }, @@ -163,4 +162,14 @@ - (void)fakeOtherSchemesAndAllSchemes { ]; } +- (void)fakeWithClientID:(id)clientID + serverClientID:(id)serverClientID + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm { + _fakeConfig[kConfigClientIDKey] = clientID; + _fakeConfig[kConfigServerClientIDKey] = serverClientID; + _fakeConfig[kConfigHostedDomainKey] = hostedDomain; + _fakeConfig[kConfigOpenIDRealmKey] = openIDRealm; +} + @end diff --git a/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m b/GoogleSignIn/Tests/Unit/GIDSignInCallbackSchemesTest.m index 67e0da61..c34536a5 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 0a74e01c..61f18f41 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -85,7 +85,7 @@ static NSString * const kClientId = @"FakeClientID"; static NSString * const kDotReversedClientId = @"FakeClientID"; static NSString * const kClientId2 = @"FakeClientID2"; -static NSString * const kAppBundleId = @"FakeBundleID"; +static NSString * const kServerClientId = @"FakeServerClientID"; static NSString * const kLanguage = @"FakeLanguage"; static NSString * const kScope = @"FakeScope"; static NSString * const kScope2 = @"FakeScope2"; @@ -334,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 @@ -342,7 +342,6 @@ - (void)setUp { forKey:kAppHasRunBeforeKey]; _signIn = [[GIDSignIn alloc] initPrivate]; - _configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; _hint = nil; __weak GIDSignInTest *weakSelf = self; @@ -394,6 +393,46 @@ - (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)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); @@ -607,10 +646,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 +681,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 +919,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 +954,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 +1275,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..00c144b7 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -19,17 +19,6 @@ 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 /// Creates an instance of this authenticator. @@ -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