From 54df79417e61e59729894f973f3bfe14e9723c84 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 17 Apr 2024 12:43:20 -0700 Subject: [PATCH 01/55] Create method verifyAccountDetailsInteractivelyWithOptions. --- .../Implementations/GIDVerifyAccountDetail.m | 57 +++++++++++++++++++ .../GoogleSignIn/GIDVerifyAccountDetail.h | 4 ++ 2 files changed, 61 insertions(+) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index ef551702..9b7f58bc 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -16,9 +16,13 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" +#import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" +#import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" + #if TARGET_OS_IOS @implementation GIDVerifyAccountDetail @@ -47,6 +51,59 @@ - (void)verifyAccountDetails:(NSArray *)accountDet // TODO(#383): Implement this method. } +// Starts authorization flow using the provided options. +- (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { + if (!options.interactive) { + return; + } + + // Ensure that a configuration is set. + 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:options]; + + [self assertValidPresentingViewController:options]; + + // If the application does not support the required URL schemes tell the developer so. + GIDSignInCallbackSchemes *schemes = + [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; + NSArray *unsupportedSchemes = [schemes unsupportedSchemes]; + if (unsupportedSchemes.count != 0) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"Your app is missing support for the following URL schemes: %@", + [unsupportedSchemes componentsJoinedByString:@", "]]; + } + // TODO(#397): Start the incremental authorization flow. +} + +#pragma mark - Helpers + +// Asserts the parameters being valid. +- (void)assertValidParameters:(GIDSignInInternalOptions *)options { + if (![options.configuration.clientID length]) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"You must specify |clientID| in |GIDConfiguration|"]; + } +} + +// Assert that the presenting view controller has been set. +- (void)assertValidPresentingViewController:(GIDSignInInternalOptions *)options { + if (!options.presentingViewController) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"|presentingViewController| must be set."]; + } +} + @end #endif // TARGET_OS_IOS diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index dca4586e..139d3fa8 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN +@class GIDConfiguration; @class GIDVerifiableAccountDetail; @class GIDVerifiedAccountDetailResult; @@ -39,6 +40,9 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// This class is used to verify a user's Google account details. @interface GIDVerifyAccountDetail : NSObject +/// The active configuration for this instance of `GIDVerifyAccountDetail`. +@property(nonatomic, nullable) GIDConfiguration *configuration; + /// Starts an interactive verification flow. /// /// The completion will be called at the end of this process. Any saved verification From 58969855dfe502092a457d2c0e2c0380fc66f204 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 18 Apr 2024 09:31:55 -0700 Subject: [PATCH 02/55] Move configuration creation methods to GIDConfiguration from GIDSignIn. --- GoogleSignIn/Sources/GIDConfiguration.m | 35 +++++++++++++++++++ GoogleSignIn/Sources/GIDSignIn.m | 34 +----------------- .../Public/GoogleSignIn/GIDConfiguration.h | 5 +++ 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/GoogleSignIn/Sources/GIDConfiguration.m b/GoogleSignIn/Sources/GIDConfiguration.m index 34ba3c8d..8a0415cb 100644 --- a/GoogleSignIn/Sources/GIDConfiguration.m +++ b/GoogleSignIn/Sources/GIDConfiguration.m @@ -26,6 +26,12 @@ // The key for the openIDRealm property to be used with NSSecureCoding. static NSString *const kOpenIDRealmKey = @"openIDRealm"; +// Info.plist config keys +static NSString *const kConfigClientIDKey = @"GIDClientID"; +static NSString *const kConfigServerClientIDKey = @"GIDServerClientID"; +static NSString *const kConfigHostedDomainKey = @"GIDHostedDomain"; +static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm"; + NS_ASSUME_NONNULL_BEGIN @implementation GIDConfiguration @@ -59,6 +65,35 @@ - (instancetype)initWithClientID:(NSString *)clientID return self; } +// 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; +} + ++ (nullable instancetype)configurationFromBundle:(NSBundle *)bundle { + // Retrieve any valid config parameters from the bundle's Info.plist. + NSString *clientID = [self configValueFromBundle:bundle forKey:kConfigClientIDKey]; + NSString *serverClientID = [self configValueFromBundle:bundle + forKey:kConfigServerClientIDKey]; + NSString *hostedDomain = [self configValueFromBundle:bundle forKey:kConfigHostedDomainKey]; + NSString *openIDRealm = [self configValueFromBundle:bundle forKey:kConfigOpenIDRealmKey]; + + // If we have at least a client ID, try to construct a configuration. + if (clientID) { + return [[self alloc] initWithClientID:clientID + serverClientID:serverClientID + hostedDomain:hostedDomain + openIDRealm:openIDRealm]; + } + + return nil; +} + // Extend NSObject's default description for easier debugging. - (NSString *)description { return [NSString stringWithFormat: diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 4b942ed9..a6c2a1e9 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -458,7 +458,7 @@ - (instancetype)initWithKeychainStore:(GTMKeychainStore *)keychainStore { // If we have a bundle, try to set the active configuration from the bundle's Info.plist. if (bundle) { - _configuration = [GIDSignIn configurationFromBundle:bundle]; + _configuration = [GIDConfiguration configurationFromBundle:bundle]; } // Check to see if the 3P app is being run for the first time after a fresh install. @@ -1019,38 +1019,6 @@ - (GIDProfileData *)profileDataWithIDToken:(OIDIDToken *)idToken { imageURL:[NSURL URLWithString:idToken.claims[kBasicProfilePictureKey]]]; } -// 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/GIDConfiguration.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h index 4902fa37..1d331f26 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h @@ -71,6 +71,11 @@ NS_ASSUME_NONNULL_BEGIN hostedDomain:(nullable NSString *)hostedDomain openIDRealm:(nullable NSString *)openIDRealm NS_DESIGNATED_INITIALIZER; +/// Try to generate a |GIDConfiguration| from an |NSBundle|'s Info.plist. +/// +/// @param bundle The bundle to generate a configuration value. ++ (nullable instancetype)configurationFromBundle:(NSBundle *)bundle; + @end NS_ASSUME_NONNULL_END From 94a4175aaf41fca753fdea9917cdd5163773c594 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 18 Apr 2024 09:33:12 -0700 Subject: [PATCH 03/55] Implement default options creation methods. --- .../Sources/GIDSignInInternalOptions.m | 1 - .../Implementations/GIDVerifyAccountDetail.m | 78 +++++-------------- .../GoogleSignIn/GIDVerifyAccountDetail.h | 18 ----- 3 files changed, 20 insertions(+), 77 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index 8be7223a..e60ce0c0 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -36,7 +36,6 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con GIDSignInInternalOptions *options = [[GIDSignInInternalOptions alloc] init]; if (options) { options->_interactive = YES; - options->_continuation = NO; options->_addScopesFlow = addScopesFlow; options->_configuration = configuration; options->_presentingViewController = presentingViewController; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 9b7f58bc..97c31953 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -31,7 +31,10 @@ - (void)verifyAccountDetails:(NSArray *)accountDet presentingViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, NSError *_Nullable error))completion { - // TODO(#383): Implement this method. + [self verifyAccountDetails:accountDetails + presentingViewController:presentingViewController + hint:nil + completion:completion]; } - (void)verifyAccountDetails:(NSArray *)accountDetails @@ -39,69 +42,28 @@ - (void)verifyAccountDetails:(NSArray *)accountDet hint:(nullable NSString *)hint completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, NSError *_Nullable error))completion { - // TODO(#383): Implement this method. -} + // Get the bundle of the current executable. + NSBundle *bundle = NSBundle.mainBundle; -- (void)verifyAccountDetails:(NSArray *)accountDetails - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, - NSError *_Nullable error))completion { - // TODO(#383): Implement this method. -} - -// Starts authorization flow using the provided options. -- (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { - if (!options.interactive) { - return; - } - - // Ensure that a configuration is set. - if (!_configuration) { - // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) - [NSException raise:NSInvalidArgumentException - format:@"No active configuration. Make sure GIDClientID is set in Info.plist."]; - return; + // If we have a bundle, try to set the active configuration from the bundle's Info.plist. + if (bundle) { + _configuration = [GIDConfiguration configurationFromBundle:bundle]; } - - // Explicitly throw exception for missing client ID here. This must come before - // scheme check because schemes rely on reverse client IDs. - [self assertValidParameters:options]; - - [self assertValidPresentingViewController:options]; - - // If the application does not support the required URL schemes tell the developer so. - GIDSignInCallbackSchemes *schemes = - [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; - NSArray *unsupportedSchemes = [schemes unsupportedSchemes]; - if (unsupportedSchemes.count != 0) { - // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) - [NSException raise:NSInvalidArgumentException - format:@"Your app is missing support for the following URL schemes: %@", - [unsupportedSchemes componentsJoinedByString:@", "]]; - } - // TODO(#397): Start the incremental authorization flow. -} -#pragma mark - Helpers + GIDSignInInternalOptions *options = + [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration + presentingViewController:presentingViewController + loginHint:hint + addScopesFlow:YES + accountDetailsToVerify:accountDetails + verifyCompletion:completion]; -// Asserts the parameters being valid. -- (void)assertValidParameters:(GIDSignInInternalOptions *)options { - if (![options.configuration.clientID length]) { - // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) - [NSException raise:NSInvalidArgumentException - format:@"You must specify |clientID| in |GIDConfiguration|"]; - } + [self verifyAccountDetailsInteractivelyWithOptions:options]; } -// Assert that the presenting view controller has been set. -- (void)assertValidPresentingViewController:(GIDSignInInternalOptions *)options { - if (!options.presentingViewController) { - // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) - [NSException raise:NSInvalidArgumentException - format:@"|presentingViewController| must be set."]; - } +// Starts authorization flow using the provided options. +- (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { + // TODO(#397): Sanity checks and start the incremental authorization flow. } @end diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 139d3fa8..f077be4d 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -72,24 +72,6 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, NSError *_Nullable error))completion; -/// Starts an interactive verification flow using the provided hint and additional scopes. -/// -/// The completion will be called at the end of this process. Any saved verification -/// state will be replaced by the result of this flow. -/// -/// @param accountDetails A list of verifiable account details. -/// @param presentingViewController The view controller used to present the flow. -/// @param hint An optional hint for the authorization server, for example the user's ID or email -/// address, to be prefilled if possible. -/// @param additionalScopes An optional array of scopes to request in addition to the basic profile scopes. -/// @param completion The optional block called asynchronously on the main queue upon completion. -- (void)verifyAccountDetails:(NSArray *)accountDetails - presentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, - NSError *_Nullable error))completion; - @end NS_ASSUME_NONNULL_END From 4c2a6431162ae429edc3eb47603bd1c7f92da869 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 18 Apr 2024 16:14:23 -0700 Subject: [PATCH 04/55] Options validation. --- .../Implementations/GIDVerifyAccountDetail.m | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 97c31953..d98c14bb 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -63,7 +63,55 @@ - (void)verifyAccountDetails:(NSArray *)accountDet // Starts authorization flow using the provided options. - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { - // TODO(#397): Sanity checks and start the incremental authorization flow. + if (!options.interactive) { + return; + } + + // Ensure that a configuration is set. + 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:options]; + + [self assertValidPresentingViewController:options]; + + // If the application does not support the required URL schemes tell the developer so. + GIDSignInCallbackSchemes *schemes = + [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; + NSArray *unsupportedSchemes = [schemes unsupportedSchemes]; + if (unsupportedSchemes.count != 0) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"Your app is missing support for the following URL schemes: %@", + [unsupportedSchemes componentsJoinedByString:@", "]]; + } + // TODO(#397): Start the incremental authorization flow. +} + +#pragma mark - Helpers + +// Asserts the parameters being valid. +- (void)assertValidParameters:(GIDSignInInternalOptions *)options { + if (![options.configuration.clientID length]) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"You must specify |clientID| in |GIDConfiguration|"]; + } +} + +// Assert that the presenting view controller has been set. +- (void)assertValidPresentingViewController:(GIDSignInInternalOptions *)options { + if (!options.presentingViewController) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"|presentingViewController| must be set."]; + } } @end From 78e175d2387b979fe2424a9c0b3c26df014b222f Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 25 Apr 2024 12:50:24 -0700 Subject: [PATCH 05/55] Add config initializers. --- .../Implementations/GIDVerifyAccountDetail.m | 31 ++++-- .../GoogleSignIn/GIDVerifyAccountDetail.h | 3 + .../Tests/Unit/GIDVerifyAccountDetailTest.m | 97 +++++++++++++++++++ 3 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index d98c14bb..0314c518 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -27,6 +27,29 @@ @implementation GIDVerifyAccountDetail +- (instancetype)initWithConfig:(GIDConfiguration *)configuration { + self = [super init]; + if (self) { + _configuration = configuration; + } + return self; +} + +- (instancetype)init { + GIDConfiguration *configuration; + // 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 = [GIDConfiguration configurationFromBundle:bundle]; + } + + return [self initWithConfig:configuration]; +} + +#pragma mark - Public methods + - (void)verifyAccountDetails:(NSArray *)accountDetails presentingViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, @@ -42,14 +65,6 @@ - (void)verifyAccountDetails:(NSArray *)accountDet hint:(nullable NSString *)hint completion:(nullable void (^)(GIDVerifiedAccountDetailResult *_Nullable verifyResult, NSError *_Nullable error))completion { - // 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 = [GIDConfiguration configurationFromBundle:bundle]; - } - GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:_configuration presentingViewController:presentingViewController diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index f077be4d..53d68e40 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -43,6 +43,9 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// The active configuration for this instance of `GIDVerifyAccountDetail`. @property(nonatomic, nullable) GIDConfiguration *configuration; +- (instancetype)initWithConfig:(GIDConfiguration *)config + NS_DESIGNATED_INITIALIZER; + /// Starts an interactive verification flow. /// /// The completion will be called at the end of this process. Any saved verification diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m new file mode 100644 index 00000000..f6545343 --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -0,0 +1,97 @@ +#import + +#if TARGET_OS_IOS +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" + +#import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" + +static NSString * const kClientId = @"FakeClientID"; + +@interface GIDVerifyAccountDetailTests : XCTestCase { +@private + // Mock |UIViewController|. + UIViewController *_presentingViewController; + + // Fake [NSBundle mainBundle]; + GIDFakeMainBundle *_fakeMainBundle; + + // The |GIDVerifyAccountDetail| object being tested. + GIDVerifyAccountDetail *_verifyAccountDetail; + + // [comment] + NSArray *_verifiableAccountDetails; + + GIDConfiguration *_configuration; +} +@end + +@implementation GIDVerifyAccountDetailTests + +#pragma mark - Lifecycle + +- (void)setUp { + [super setUp]; + + _presentingViewController = [[UIViewController alloc] init]; + +// _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + + GIDVerifiableAccountDetail *ageOver18Detail = [[GIDVerifiableAccountDetail alloc] initWithAccountDetailType:GIDAccountDetailTypeAgeOver18]; + _verifiableAccountDetails = @[ageOver18Detail]; + + _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; + [_fakeMainBundle startFakingWithClientID:kClientId]; + [_fakeMainBundle fakeAllSchemesSupported]; +} + + +#pragma mark - Tests + +- (void)testPresentingViewControllerException { + _presentingViewController = nil; + + XCTAssertThrows([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]); +} + +- (void)testClientIDMissingException { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; +#pragma GCC diagnostic pop + BOOL threw = NO; + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + threw = YES; + XCTAssertEqualObjects(exception.description, + @"You must specify |clientID| in |GIDConfiguration|"); + } @finally { + } + XCTAssert(threw); +} + +- (void)testSchemesNotSupportedException { + [_fakeMainBundle fakeMissingAllSchemes]; + BOOL threw = NO; + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + threw = YES; + XCTAssertEqualObjects(exception.description, + @"Your app is missing support for the following URL schemes: " + "fakeclientid"); + } @finally { + } + XCTAssert(threw); +} + +@end + +#endif // TARGET_OS_IOS From a5b9a6163885df39f67800945abff5577d4d8dce Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 25 Apr 2024 14:50:17 -0700 Subject: [PATCH 06/55] Fix spacing. --- .../Implementations/GIDVerifyAccountDetail.m | 14 ++---- .../GoogleSignIn/GIDVerifyAccountDetail.h | 2 +- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 49 ++++++++++++------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 1a637f70..7598d456 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -38,10 +38,7 @@ - (instancetype)initWithConfig:(GIDConfiguration *)configuration { - (instancetype)init { GIDConfiguration *configuration; - // 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 = [GIDConfiguration configurationFromBundle:bundle]; } @@ -77,26 +74,25 @@ - (void)verifyAccountDetails:(NSArray *)accountDet [self verifyAccountDetailsInteractivelyWithOptions:options]; } -// Starts authorization flow using the provided options. - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { if (!options.interactive) { return; } - + // Ensure that a configuration is set. if (!_configuration) { // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) [NSException raise:NSInvalidArgumentException format:@"No active configuration. Make sure GIDClientID is set in Info.plist."]; - return; + return; } - + // Explicitly throw exception for missing client ID here. This must come before // scheme check because schemes rely on reverse client IDs. [self assertValidParameters:options]; - + [self assertValidPresentingViewController:options]; - + // If the application does not support the required URL schemes tell the developer so. GIDSignInCallbackSchemes *schemes = [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 53d68e40..ff967ac8 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -44,7 +44,7 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve @property(nonatomic, nullable) GIDConfiguration *configuration; - (instancetype)initWithConfig:(GIDConfiguration *)config - NS_DESIGNATED_INITIALIZER; +NS_DESIGNATED_INITIALIZER; /// Starts an interactive verification flow. /// diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index f6545343..2d1de588 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -1,3 +1,17 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #import #if TARGET_OS_IOS @@ -9,19 +23,17 @@ @interface GIDVerifyAccountDetailTests : XCTestCase { @private - // Mock |UIViewController|. + // The |UIViewController| object being tested. UIViewController *_presentingViewController; - // Fake [NSBundle mainBundle]; + // Fake [NSBundle mainBundle]. GIDFakeMainBundle *_fakeMainBundle; // The |GIDVerifyAccountDetail| object being tested. GIDVerifyAccountDetail *_verifyAccountDetail; - // [comment] + // The list of account details when testing [GIDVerifiableAccountDetail]. NSArray *_verifiableAccountDetails; - - GIDConfiguration *_configuration; } @end @@ -34,7 +46,6 @@ - (void)setUp { _presentingViewController = [[UIViewController alloc] init]; -// _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; GIDVerifiableAccountDetail *ageOver18Detail = [[GIDVerifiableAccountDetail alloc] initWithAccountDetailType:GIDAccountDetailTypeAgeOver18]; @@ -59,20 +70,20 @@ - (void)testPresentingViewControllerException { - (void)testClientIDMissingException { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" - _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; + _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - BOOL threw = NO; - @try { - [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil]; - } @catch (NSException *exception) { - threw = YES; - XCTAssertEqualObjects(exception.description, - @"You must specify |clientID| in |GIDConfiguration|"); - } @finally { - } - XCTAssert(threw); + BOOL threw = NO; + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + threw = YES; + XCTAssertEqualObjects(exception.description, + @"You must specify |clientID| in |GIDConfiguration|"); + } @finally { + } + XCTAssert(threw); } - (void)testSchemesNotSupportedException { From d70400a93098d3e1baf724f15cc04c43e47f0115 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 25 Apr 2024 15:23:37 -0700 Subject: [PATCH 07/55] Add import to use GIDAccountDetailTypeAgeOver18. --- .../Implementations/GIDVerifyAccountDetail.m | 2 ++ GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m | 1 + 2 files changed, 3 insertions(+) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 7598d456..8bfb4a61 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -74,6 +74,8 @@ - (void)verifyAccountDetails:(NSArray *)accountDet [self verifyAccountDetailsInteractivelyWithOptions:options]; } +#pragma mark - Authentication flow + - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions *)options { if (!options.interactive) { return; diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 2d1de588..e83cfbb1 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -16,6 +16,7 @@ #if TARGET_OS_IOS #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" From f858d20104f665499ead2647cd643328ebf60740 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 25 Apr 2024 15:38:08 -0700 Subject: [PATCH 08/55] Import GIDConfiguration to test file. --- .../Implementations/GIDVerifyAccountDetail.m | 1 - GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 8bfb4a61..8cc5c438 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -16,7 +16,6 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index e83cfbb1..2d41e199 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -15,6 +15,7 @@ #import #if TARGET_OS_IOS +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" From 4a97c00b861ff007e6146253fae1380f09e5f7ee Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 29 Apr 2024 15:52:07 -0700 Subject: [PATCH 09/55] Create OIDAuthorizationRequest. --- .../Implementations/GIDVerifyAccountDetail.m | 83 ++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 8cc5c438..7af2ee25 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -20,17 +20,59 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" +#import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" +#import "GoogleSignIn/Sources/GIDSignInPreferences.h" + +@import GTMAppAuth; + +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GTMSessionFetcherCore; +#else +#import +#import +#import +#endif #if TARGET_OS_IOS -@implementation GIDVerifyAccountDetail +// The URL template for the authorization endpoint. +static NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; + +// The URL template for the token endpoint. +static NSString *const kTokenURLTemplate = @"https://%@/token"; + +// Expected path in the URL scheme to be handled. +static NSString *const kBrowserCallbackPath = @"/oauth2callback"; + +// The EMM support version +static NSString *const kEMMVersion = @"1"; + +// Parameters for the auth and token exchange endpoints. +static NSString *const kAudienceParameter = @"audience"; +static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; +static NSString *const kLoginHintParameter = @"login_hint"; +static NSString *const kHostedDomainParameter = @"hd"; + +@implementation GIDVerifyAccountDetail { + // AppAuth configuration object. + OIDServiceConfiguration *_appAuthConfiguration; +} - (instancetype)initWithConfig:(GIDConfiguration *)configuration { self = [super init]; if (self) { _configuration = configuration; + + NSString *authorizationEndpointURL = [NSString stringWithFormat:kAuthorizationURLTemplate, + [GIDSignInPreferences googleAuthorizationServer]]; + NSString *tokenEndpointURL = [NSString stringWithFormat:kTokenURLTemplate, + [GIDSignInPreferences googleTokenServer]]; + _appAuthConfiguration = [[OIDServiceConfiguration alloc] + initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] + tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; } return self; } @@ -104,7 +146,44 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * format:@"Your app is missing support for the following URL schemes: %@", [unsupportedSchemes componentsJoinedByString:@", "]]; } - // TODO(#397): Start the incremental authorization flow. + NSURL *redirectURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@:%@", + [schemes clientIdentifierScheme], + kBrowserCallbackPath]]; + + NSMutableDictionary *additionalParameters = [@{} mutableCopy]; + additionalParameters[kIncludeGrantedScopesParameter] = @"true"; + if (options.configuration.serverClientID) { + additionalParameters[kAudienceParameter] = options.configuration.serverClientID; + } + if (options.loginHint) { + additionalParameters[kLoginHintParameter] = options.loginHint; + } + if (options.configuration.hostedDomain) { + additionalParameters[kHostedDomainParameter] = options.configuration.hostedDomain; + } + + [additionalParameters addEntriesFromDictionary: + [GIDEMMSupport parametersWithParameters:options.extraParams + emmSupport:kEMMVersion + isPasscodeInfoRequired:NO]]; + additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); + additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); + + NSMutableArray *scopes; + for (GIDVerifiableAccountDetail *detail in options.accountDetailsToVerify) { + NSString *scopeString = [detail scope]; + if (scopeString) { + [scopes addObject:scopeString]; + } + } + + OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + clientId:options.configuration.clientID + scopes:scopes + redirectURL:redirectURL + responseType:OIDResponseTypeCode + additionalParameters:additionalParameters]; } #pragma mark - Helpers From c4d0a163a4c46bc8fdca95a26132172488a9c797 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 30 Apr 2024 14:03:25 -0700 Subject: [PATCH 10/55] Add tests for config initializers. --- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 2d41e199..bca49f74 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -22,6 +22,9 @@ #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" static NSString * const kClientId = @"FakeClientID"; +static NSString * const kServerClientId = @"FakeServerClientID"; +static NSString * const kOpenIDRealm = @"FakeRealm"; +static NSString * const kFakeHostedDomain = @"fakehosteddomain.com"; @interface GIDVerifyAccountDetailTests : XCTestCase { @private @@ -61,6 +64,48 @@ - (void)setUp { #pragma mark - Tests +- (void)testInit { + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNotNil(verifyAccountDetail.configuration); + XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); + XCTAssertNil(verifyAccountDetail.configuration.serverClientID); + XCTAssertNil(verifyAccountDetail.configuration.hostedDomain); + XCTAssertNil(verifyAccountDetail.configuration.openIDRealm); + +} + +- (void)testInit_noConfig { + [_fakeMainBundle fakeWithClientID:nil + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNil(verifyAccountDetail.configuration); +} + + +- (void)testInit_fullConfig { + [_fakeMainBundle fakeWithClientID:kClientId + serverClientID:kServerClientId + hostedDomain:kFakeHostedDomain + openIDRealm:kOpenIDRealm]; + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNotNil(verifyAccountDetail.configuration); + XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); + XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); + XCTAssertEqual(verifyAccountDetail.configuration.hostedDomain, kFakeHostedDomain); + XCTAssertEqual(verifyAccountDetail.configuration.openIDRealm, kOpenIDRealm); +} + +- (void)testInit_invalidConfig { + [_fakeMainBundle fakeWithClientID:@[ @"bad", @"config", @"values" ] + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNil(verifyAccountDetail.configuration); +} + - (void)testPresentingViewControllerException { _presentingViewController = nil; From e04a1ea934dd56d49e5dd26651d3a0f6396306d8 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 1 May 2024 13:15:56 -0700 Subject: [PATCH 11/55] Add in initializer with config tests. --- .../Implementations/GIDVerifyAccountDetail.m | 2 +- .../GoogleSignIn/GIDVerifyAccountDetail.h | 2 +- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 93 +++++++++++++------ 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 8cc5c438..940097a6 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -27,7 +27,7 @@ @implementation GIDVerifyAccountDetail -- (instancetype)initWithConfig:(GIDConfiguration *)configuration { +- (instancetype)initWithConfig:(nullable GIDConfiguration *)configuration { self = [super init]; if (self) { _configuration = configuration; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index ff967ac8..424124a2 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -43,7 +43,7 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// The active configuration for this instance of `GIDVerifyAccountDetail`. @property(nonatomic, nullable) GIDConfiguration *configuration; -- (instancetype)initWithConfig:(GIDConfiguration *)config +- (instancetype)initWithConfig:(nullable GIDConfiguration *)config NS_DESIGNATED_INITIALIZER; /// Starts an interactive verification flow. diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 2d41e199..cbc98976 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -22,6 +22,9 @@ #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" static NSString * const kClientId = @"FakeClientID"; +static NSString * const kServerClientId = @"FakeServerClientID"; +static NSString * const kOpenIDRealm = @"FakeRealm"; +static NSString * const kFakeHostedDomain = @"fakehosteddomain.com"; @interface GIDVerifyAccountDetailTests : XCTestCase { @private @@ -54,13 +57,61 @@ - (void)setUp { _verifiableAccountDetails = @[ageOver18Detail]; _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; - [_fakeMainBundle startFakingWithClientID:kClientId]; - [_fakeMainBundle fakeAllSchemesSupported]; } #pragma mark - Tests +- (void)testInit { + [_fakeMainBundle startFakingWithClientID:kClientId]; + + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNotNil(verifyAccountDetail.configuration); + XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); + XCTAssertNil(verifyAccountDetail.configuration.serverClientID); + XCTAssertNil(verifyAccountDetail.configuration.hostedDomain); + XCTAssertNil(verifyAccountDetail.configuration.openIDRealm); + +} + +- (void)testInit_noConfig { + [_fakeMainBundle startFakingWithClientID:kClientId]; + [_fakeMainBundle fakeWithClientID:nil + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + + XCTAssertNil(verifyAccountDetail.configuration); +} + + +- (void)testInit_fullConfig { + [_fakeMainBundle startFakingWithClientID:kClientId]; + [_fakeMainBundle fakeWithClientID:kClientId + serverClientID:kServerClientId + hostedDomain:kFakeHostedDomain + openIDRealm:kOpenIDRealm]; + + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNotNil(verifyAccountDetail.configuration); + XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); + XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); + XCTAssertEqual(verifyAccountDetail.configuration.hostedDomain, kFakeHostedDomain); + XCTAssertEqual(verifyAccountDetail.configuration.openIDRealm, kOpenIDRealm); +} + +- (void)testInit_invalidConfig { + [_fakeMainBundle startFakingWithClientID:kClientId]; + [_fakeMainBundle fakeWithClientID:@[ @"bad", @"config", @"values" ] + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; + XCTAssertNil(verifyAccountDetail.configuration); +} + - (void)testPresentingViewControllerException { _presentingViewController = nil; @@ -74,35 +125,21 @@ - (void)testClientIDMissingException { #pragma GCC diagnostic ignored "-Wnonnull" _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - BOOL threw = NO; - @try { - [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil]; - } @catch (NSException *exception) { - threw = YES; - XCTAssertEqualObjects(exception.description, - @"You must specify |clientID| in |GIDConfiguration|"); - } @finally { - } - XCTAssert(threw); + + XCTAssertThrowsSpecificNamed( + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController completion:nil], + NSException, + NSInvalidArgumentException, + @"You must specify |clientID| in |GIDConfiguration|"); } - (void)testSchemesNotSupportedException { - [_fakeMainBundle fakeMissingAllSchemes]; - BOOL threw = NO; - @try { - [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil]; - } @catch (NSException *exception) { - threw = YES; - XCTAssertEqualObjects(exception.description, - @"Your app is missing support for the following URL schemes: " - "fakeclientid"); - } @finally { - } - XCTAssert(threw); + XCTAssertThrowsSpecificNamed( + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController completion:nil], + NSException, + NSInvalidArgumentException, + @"Your app is missing support for the following URL schemes: " + "fakeclientid"); } @end From 93fb453e6ced7a3a75e0b0d00d2cd39a4837d12f Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 2 May 2024 10:26:23 -0700 Subject: [PATCH 12/55] Make used variables properties. --- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index cbc98976..46337649 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -26,20 +26,18 @@ static NSString * const kOpenIDRealm = @"FakeRealm"; static NSString * const kFakeHostedDomain = @"fakehosteddomain.com"; -@interface GIDVerifyAccountDetailTests : XCTestCase { -@private - // The |UIViewController| object being tested. - UIViewController *_presentingViewController; +@interface GIDVerifyAccountDetailTests : XCTestCase +// The |UIViewController| object being tested. +@property UIViewController *presentingViewController; - // Fake [NSBundle mainBundle]. - GIDFakeMainBundle *_fakeMainBundle; +// Fake [NSBundle mainBundle]. +@property GIDFakeMainBundle *fakeMainBundle; - // The |GIDVerifyAccountDetail| object being tested. - GIDVerifyAccountDetail *_verifyAccountDetail; +// The |GIDVerifyAccountDetail| object being tested. +@property GIDVerifyAccountDetail *verifyAccountDetail; - // The list of account details when testing [GIDVerifiableAccountDetail]. - NSArray *_verifiableAccountDetails; -} +// The list of account details when testing [GIDVerifiableAccountDetail]. +@property NSArray *verifiableAccountDetails; @end @implementation GIDVerifyAccountDetailTests @@ -71,7 +69,6 @@ - (void)testInit { XCTAssertNil(verifyAccountDetail.configuration.serverClientID); XCTAssertNil(verifyAccountDetail.configuration.hostedDomain); XCTAssertNil(verifyAccountDetail.configuration.openIDRealm); - } - (void)testInit_noConfig { From 066fa07f5b09b03ad72c19a4082e2168b660fe69 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 2 May 2024 15:39:52 -0700 Subject: [PATCH 13/55] Add TODO for request/response handling tests. --- GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 46337649..d7c6d87f 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -109,6 +109,8 @@ - (void)testInit_invalidConfig { XCTAssertNil(verifyAccountDetail.configuration); } +// TODO(#405): Write tests for request and response handling. + - (void)testPresentingViewControllerException { _presentingViewController = nil; From dc6560b7e569615b72f212572cf572b5d4ebb9d3 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 2 May 2024 18:18:38 -0700 Subject: [PATCH 14/55] Exclude MacOS for `GIDEMMSupport` use. --- .../Implementations/GIDVerifyAccountDetail.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 2ff65fd2..45598e30 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -36,7 +36,7 @@ #import #endif -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST // The URL template for the authorization endpoint. static NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; @@ -208,4 +208,4 @@ - (void)assertValidPresentingViewController:(GIDSignInInternalOptions *)options @end -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST From fa7845ccfbd65f0abefad46cb7cdbd7a97b56122 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 2 May 2024 18:42:39 -0700 Subject: [PATCH 15/55] Silence unused 'request' variable for now until response is implemented. --- .../Implementations/GIDVerifyAccountDetail.m | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 45598e30..6bdae75f 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -177,13 +177,14 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * } } - OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration - clientId:options.configuration.clientID - scopes:scopes - redirectURL:redirectURL - responseType:OIDResponseTypeCode - additionalParameters:additionalParameters]; + // TODO(#405): Use request variable to present request and process response. + __unused OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + clientId:options.configuration.clientID + scopes:scopes + redirectURL:redirectURL + responseType:OIDResponseTypeCode + additionalParameters:additionalParameters]; } #pragma mark - Helpers From 986c1daf0252eb72c947409de5d9a57db5b312d8 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 6 May 2024 11:34:34 -0700 Subject: [PATCH 16/55] Implement method to process authorization response. --- .../Implementations/GIDVerifyAccountDetail.m | 173 +++++++++++++++++- .../GoogleSignIn/GIDVerifyAccountDetail.h | 13 ++ 2 files changed, 177 insertions(+), 9 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 6bdae75f..ea3c31f6 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -19,11 +19,16 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" +#import "GoogleSignIn/Sources/GIDCallbackQueue.h" +#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" + +//#import "GoogleSignIn/Sources/GIDProfileData_Private.h" @import GTMAppAuth; @@ -31,9 +36,11 @@ @import AppAuth; @import GTMSessionFetcherCore; #else +#import #import #import #import +#import #endif #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -50,15 +57,44 @@ // The EMM support version static NSString *const kEMMVersion = @"1"; +// The error code for Google Identity. +NSErrorDomain const kGIDVerifyErrorDomain = @"com.google.GIDVerify"; + +// Error string for user cancelations. +static NSString *const kUserCanceledError = @"The user canceled the sign-in flow."; + +// Parameters in the callback URL coming back from browser. +static NSString *const kOAuth2ErrorKeyName = @"error"; +static NSString *const kOAuth2AccessDenied = @"access_denied"; +static NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; + // Parameters for the auth and token exchange endpoints. static NSString *const kAudienceParameter = @"audience"; static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; static NSString *const kLoginHintParameter = @"login_hint"; static NSString *const kHostedDomainParameter = @"hd"; +// Minimum time to expiration for a restored access token. +static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; + +// The callback queue used for authentication flow. +@interface GIDVerifyAuthFlow : GIDCallbackQueue + +@property(nonatomic, strong, nullable) OIDAuthState *authState; +@property(nonatomic, strong, nullable) NSError *error; +@property(nonatomic, copy, nullable) NSString *emmSupport; +@property(nonatomic, nullable) GIDProfileData *profileData; + +@end + +@implementation GIDVerifyAuthFlow +@end + @implementation GIDVerifyAccountDetail { // AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; + // AppAuth external user-agent session state. + id _currentAuthorizationFlow; } - (instancetype)initWithConfig:(nullable GIDConfiguration *)configuration { @@ -67,12 +103,12 @@ - (instancetype)initWithConfig:(nullable GIDConfiguration *)configuration { _configuration = configuration; NSString *authorizationEndpointURL = [NSString stringWithFormat:kAuthorizationURLTemplate, - [GIDSignInPreferences googleAuthorizationServer]]; + [GIDSignInPreferences googleAuthorizationServer]]; NSString *tokenEndpointURL = [NSString stringWithFormat:kTokenURLTemplate, - [GIDSignInPreferences googleTokenServer]]; + [GIDSignInPreferences googleTokenServer]]; _appAuthConfiguration = [[OIDServiceConfiguration alloc] - initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] - tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; + initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] + tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; } return self; } @@ -163,9 +199,9 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * } [additionalParameters addEntriesFromDictionary: - [GIDEMMSupport parametersWithParameters:options.extraParams - emmSupport:kEMMVersion - isPasscodeInfoRequired:NO]]; + [GIDEMMSupport parametersWithParameters:options.extraParams + emmSupport:kEMMVersion + isPasscodeInfoRequired:NO]]; additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); @@ -177,18 +213,137 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * } } - // TODO(#405): Use request variable to present request and process response. - __unused OIDAuthorizationRequest *request = + OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration clientId:options.configuration.clientID scopes:scopes redirectURL:redirectURL responseType:OIDResponseTypeCode additionalParameters:additionalParameters]; + + _currentAuthorizationFlow = [OIDAuthorizationService + presentAuthorizationRequest:request + presentingViewController:options.presentingViewController + callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, + NSError *_Nullable error) { + [self processAuthorizationResponse:authorizationResponse + error:error + emmSupport:kEMMVersion]; + }]; +} + +- (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + error:(NSError *)error + emmSupport:(NSString *)emmSupport{ + GIDVerifyAuthFlow *authFlow = [[GIDVerifyAuthFlow alloc] init]; + authFlow.emmSupport = emmSupport; + + if (authorizationResponse) { + if (authorizationResponse.authorizationCode.length) { + authFlow.authState = [[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse]; + // perform auth code exchange + [self maybeFetchToken:authFlow]; + } else { + // There was a failure, convert to appropriate error code. + NSString *errorString; + GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + NSDictionary *params = authorizationResponse.additionalParameters; + + if (authFlow.emmSupport) { + [authFlow wait]; + BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] handleErrorFromResponse:params completion:^{ + [authFlow next]; + }]; + if (isEMMError) { + errorCode = kGIDVerifyErrorCodeEMM; + } + } + errorString = (NSString *)params[kOAuth2ErrorKeyName]; + if ([errorString isEqualToString:kOAuth2AccessDenied]) { + errorCode = kGIDVerifyErrorCodeCanceled; + } + + authFlow.error = [self errorWithString:errorString code:errorCode]; + } + } else { + NSString *errorString = [error localizedDescription]; + GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { + errorString = kUserCanceledError; + errorCode = kGIDVerifyErrorCodeCanceled; + } + authFlow.error = [self errorWithString:errorString code:errorCode]; + } + + // completion and decode +} + +// Fetches the access token if necessary as part of the auth flow. +- (void)maybeFetchToken:(GIDVerifyAuthFlow *)authFlow { + OIDAuthState *authState = authFlow.authState; + // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. + if (authFlow.error || + (authState.lastTokenResponse.accessToken && + [authState.lastTokenResponse.accessTokenExpirationDate timeIntervalSinceNow] > + kMinimumRestoredAccessTokenTimeToExpire)) { + return; + } + NSMutableDictionary *additionalParameters = [@{} mutableCopy]; + if (_configuration.serverClientID) { + additionalParameters[kAudienceParameter] = _configuration.serverClientID; + } + NSDictionary *params = + authState.lastAuthorizationResponse.additionalParameters; + NSString *passcodeInfoRequired = (NSString *)params[kEMMPasscodeInfoRequiredKeyName]; + [additionalParameters addEntriesFromDictionary: + [GIDEMMSupport parametersWithParameters:@{} + emmSupport:authFlow.emmSupport + isPasscodeInfoRequired:passcodeInfoRequired.length > 0]]; + additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); + additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); + + OIDTokenRequest *tokenRequest; + if (!authState.lastTokenResponse.accessToken && + authState.lastAuthorizationResponse.authorizationCode) { + tokenRequest = [authState.lastAuthorizationResponse + tokenExchangeRequestWithAdditionalParameters:additionalParameters]; + } else { + [additionalParameters + addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; + tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; + } + + [authFlow wait]; + [OIDAuthorizationService + performTokenRequest:tokenRequest + callback:^(OIDTokenResponse *_Nullable tokenResponse, + NSError *_Nullable error) { + [authState updateWithTokenResponse:tokenResponse error:error]; + authFlow.error = error; + + if (authFlow.emmSupport) { + [GIDEMMSupport handleTokenFetchEMMError:error completion:^(NSError *error) { + authFlow.error = error; + [authFlow next]; + }]; + } else { + [authFlow next]; + } + }]; } #pragma mark - Helpers +- (NSError *)errorWithString:(NSString *)errorString code:(GIDVerifyErrorCode)code { + if (errorString == nil) { + errorString = @"Unknown error"; + } + NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; + return [NSError errorWithDomain:kGIDVerifyErrorDomain + code:code + userInfo:errorDict]; +} + // Asserts the parameters being valid. - (void)assertValidParameters:(GIDSignInInternalOptions *)options { if (![options.configuration.clientID length]) { diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 424124a2..75c51634 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -32,6 +32,19 @@ NS_ASSUME_NONNULL_BEGIN @class GIDVerifiableAccountDetail; @class GIDVerifiedAccountDetailResult; +/// The error domain for `NSError`s returned by the Google Sign-In SDK. +extern NSErrorDomain const kGIDVerifyErrorDomain; + +/// A list of potential error codes returned from the Google Sign-In SDK. +typedef NS_ERROR_ENUM(kGIDVerifyErrorDomain, GIDVerifyErrorCode) { + /// Indicates an unknown error has occurred. + kGIDVerifyErrorCodeUnknown = -1, + /// Indicates the user canceled the verification request. + kGIDVerifyErrorCodeCanceled = -2, + /// Indicates an Enterprise Mobility Management related error has occurred. + kGIDVerifyErrorCodeEMM = -3, +}; + /// Represents a completion block that takes a `GIDVerifiedAccountDetailResult` on success or an /// error if the operation was unsuccessful. typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable verifiedResult, From 8bfd659eb794fa74c8967923ebe873dfe3c9c0f0 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 7 May 2024 15:02:53 -0700 Subject: [PATCH 17/55] Add tests for config initializer and current user exception. --- .../Implementations/GIDVerifyAccountDetail.m | 11 +++ .../Tests/Unit/GIDVerifyAccountDetailTest.m | 85 +++++++++++++++++-- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 940097a6..72b9bc83 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -88,6 +88,8 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * return; } + [self assertValidCurrentUser]; + // Explicitly throw exception for missing client ID here. This must come before // scheme check because schemes rely on reverse client IDs. [self assertValidParameters:options]; @@ -109,6 +111,15 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * #pragma mark - Helpers +// Assert that a current user exists. +- (void)assertValidCurrentUser { + if (!GIDSignIn.sharedInstance.currentUser) { + // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) + [NSException raise:NSInvalidArgumentException + format:@"|currentUser| must be set to verify."]; + } +} + // Asserts the parameters being valid. - (void)assertValidParameters:(GIDSignInInternalOptions *)options { if (![options.configuration.clientID length]) { diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 46337649..c7c14cdb 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -19,7 +19,11 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" +#import "GoogleSignIn/Sources/GIDSignIn_Private.h" +#import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" + #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" +#import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" static NSString * const kClientId = @"FakeClientID"; static NSString * const kServerClientId = @"FakeServerClientID"; @@ -51,7 +55,9 @@ - (void)setUp { _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; - GIDVerifiableAccountDetail *ageOver18Detail = [[GIDVerifiableAccountDetail alloc] initWithAccountDetailType:GIDAccountDetailTypeAgeOver18]; + GIDVerifiableAccountDetail *ageOver18Detail = [[GIDVerifiableAccountDetail alloc] + initWithAccountDetailType: + GIDAccountDetailTypeAgeOver18]; _verifiableAccountDetails = @[ageOver18Detail]; _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; @@ -109,12 +115,60 @@ - (void)testInit_invalidConfig { XCTAssertNil(verifyAccountDetail.configuration); } +- (void)testInitWithConfig_noConfig { + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] initWithConfig:nil]; + XCTAssertNil(verifyAccountDetail.configuration); +} + +- (void)testInitWithConfig_fullConfig { + GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:kClientId + serverClientID:kServerClientId + hostedDomain:kFakeHostedDomain + openIDRealm:kOpenIDRealm]; + + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] + initWithConfig:configuration]; + XCTAssertNotNil(verifyAccountDetail.configuration); + XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); + XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); + XCTAssertEqual(verifyAccountDetail.configuration.hostedDomain, kFakeHostedDomain); + XCTAssertEqual(verifyAccountDetail.configuration.openIDRealm, kOpenIDRealm); +} + +- (void)testCurrentUserException { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; +#pragma GCC diagnostic pop + + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = nil; + + XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil], + NSException, + NSInvalidArgumentException, + @"|currentUser| must be set to verify."); +} + - (void)testPresentingViewControllerException { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; +#pragma GCC diagnostic pop _presentingViewController = nil; - XCTAssertThrows([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil]); + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + + XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil], + NSException, + NSInvalidArgumentException, + @"|presentingViewController| must be set."); } - (void)testClientIDMissingException { @@ -123,16 +177,31 @@ - (void)testClientIDMissingException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - XCTAssertThrowsSpecificNamed( - [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController completion:nil], + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + + XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil], NSException, NSInvalidArgumentException, @"You must specify |clientID| in |GIDConfiguration|"); } - (void)testSchemesNotSupportedException { - XCTAssertThrowsSpecificNamed( - [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController completion:nil], +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; +#pragma GCC diagnostic pop + + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + + XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil], NSException, NSInvalidArgumentException, @"Your app is missing support for the following URL schemes: " From 9376a4b7904f7fb364852f28a1114607498be528 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 7 May 2024 17:41:48 -0700 Subject: [PATCH 18/55] Create fake main bundle initializer and modify tests. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 9 ++- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 31 ++++++++-- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 62 +++++++++++-------- 3 files changed, 71 insertions(+), 31 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 3086880e..559cfbb7 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -22,12 +22,19 @@ */ @interface GIDFakeMainBundle : NSObject +- (instancetype)initWithClientID:(id)clientID + serverClientID:(id)serverClientID + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm; + +- (void)startFaking; + /** * @fn startFakingWithClientID: * @brief Starts faking [NSBundle mainBundle] * @param clientID The fake client idenfitier for the app. */ -- (void)startFakingWithClientID:(NSString *)clientID; +- (void)startFakingWithClientID:(nullable NSString *)clientID; /** * @fn stopFaking diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index d017e60c..e66c29df 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -37,16 +37,31 @@ @implementation GIDFakeMainBundle { NSMutableDictionary *_fakeConfig; } -- (void)startFakingWithClientID:(NSString *)clientId { - _clientId = clientId; +- (instancetype)initWithClientID:(id)clientID + serverClientID:(id)serverClientID + hostedDomain:(id)hostedDomain + openIDRealm:(id)openIDRealm { + self = [super init]; + + if (self) { + _clientId = clientID; + + _fakeConfig = clientID ? [@{ @"GIDClientID" : clientID } mutableCopy] : [@{} mutableCopy]; + + _fakeConfig[kConfigClientIDKey] = clientID; + _fakeConfig[kConfigServerClientIDKey] = serverClientID; + _fakeConfig[kConfigHostedDomainKey] = hostedDomain; + _fakeConfig[kConfigOpenIDRealmKey] = openIDRealm; + } + return self; +} +- (void)startFaking { _fakedKeys = @[ kCFBundleURLTypesKey, kConfigClientIDKey, kConfigServerClientIDKey, kConfigHostedDomainKey, kConfigOpenIDRealmKey ]; - - _fakeConfig = [@{ @"GIDClientID" : clientId } mutableCopy]; [GULSwizzler swizzleClass:[NSBundle class] selector:@selector(objectForInfoDictionaryKey:) @@ -62,6 +77,14 @@ - (void)startFakingWithClientID:(NSString *)clientId { }]; } +- (void)startFakingWithClientID:(nullable NSString *)clientId { + _clientId = clientId; + + _fakeConfig = clientId ? [@{ @"GIDClientID" : clientId } mutableCopy] : [@{} mutableCopy]; + + [self startFaking]; +} + - (void)stopFaking { [GULSwizzler unswizzleClass:[NSBundle class] selector:@selector(objectForInfoDictionaryKey:) diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index c7c14cdb..ea642f04 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -25,6 +25,12 @@ #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" #import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" +#ifdef SWIFT_PACKAGE +@import OCMock; +#else +#import +#endif + static NSString * const kClientId = @"FakeClientID"; static NSString * const kServerClientId = @"FakeServerClientID"; static NSString * const kOpenIDRealm = @"FakeRealm"; @@ -60,7 +66,10 @@ - (void)setUp { GIDAccountDetailTypeAgeOver18]; _verifiableAccountDetails = @[ageOver18Detail]; - _fakeMainBundle = [[GIDFakeMainBundle alloc] init]; + _fakeMainBundle = [[GIDFakeMainBundle alloc] initWithClientID:kClientId + serverClientID:kServerClientId + hostedDomain:kFakeHostedDomain + openIDRealm:kOpenIDRealm]; } @@ -78,11 +87,7 @@ - (void)testInit { } - (void)testInit_noConfig { - [_fakeMainBundle startFakingWithClientID:kClientId]; - [_fakeMainBundle fakeWithClientID:nil - serverClientID:nil - hostedDomain:nil - openIDRealm:nil]; + [_fakeMainBundle startFakingWithClientID:nil]; GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNil(verifyAccountDetail.configuration); @@ -90,11 +95,7 @@ - (void)testInit_noConfig { - (void)testInit_fullConfig { - [_fakeMainBundle startFakingWithClientID:kClientId]; - [_fakeMainBundle fakeWithClientID:kClientId - serverClientID:kServerClientId - hostedDomain:kFakeHostedDomain - openIDRealm:kOpenIDRealm]; + [_fakeMainBundle startFaking]; GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNotNil(verifyAccountDetail.configuration); @@ -105,11 +106,12 @@ - (void)testInit_fullConfig { } - (void)testInit_invalidConfig { - [_fakeMainBundle startFakingWithClientID:kClientId]; - [_fakeMainBundle fakeWithClientID:@[ @"bad", @"config", @"values" ] - serverClientID:nil - hostedDomain:nil - openIDRealm:nil]; + _fakeMainBundle = [[GIDFakeMainBundle alloc] initWithClientID:@[ @"bad", @"config", @"values" ] + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; + [_fakeMainBundle startFaking]; + GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNil(verifyAccountDetail.configuration); @@ -127,7 +129,7 @@ - (void)testInitWithConfig_fullConfig { openIDRealm:kOpenIDRealm]; GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] - initWithConfig:configuration]; + initWithConfig:configuration]; XCTAssertNotNil(verifyAccountDetail.configuration); XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); @@ -142,7 +144,7 @@ - (void)testCurrentUserException { #pragma GCC diagnostic pop OIDAuthState *authState = [OIDAuthState testInstance]; - GIDSignIn.sharedInstance.currentUser = nil; +// GIDSignIn.sharedInstance.currentUser = nil; XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController @@ -160,8 +162,16 @@ - (void)testPresentingViewControllerException { _presentingViewController = nil; OIDAuthState *authState = [OIDAuthState testInstance]; - GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState - profileData:nil]; +// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState +// profileData:nil]; + +// GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; + id signIn = OCMClassMock([GIDSignIn class]); + OCMStub([signIn sharedInstance]).andReturn(signIn); + + GIDGoogleUser *currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + OCMStub([signIn currentUser]).andReturn(currentUser); XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController @@ -177,9 +187,9 @@ - (void)testClientIDMissingException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - OIDAuthState *authState = [OIDAuthState testInstance]; - GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState - profileData:nil]; +// OIDAuthState *authState = [OIDAuthState testInstance]; +// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState +// profileData:nil]; XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController @@ -195,9 +205,9 @@ - (void)testSchemesNotSupportedException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; #pragma GCC diagnostic pop - OIDAuthState *authState = [OIDAuthState testInstance]; - GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState - profileData:nil]; +// OIDAuthState *authState = [OIDAuthState testInstance]; +// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState +// profileData:nil]; XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails presentingViewController:_presentingViewController From 4cebc057ffc001435e3390d044ec38b1d55b9a51 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 8 May 2024 15:20:12 -0700 Subject: [PATCH 19/55] Remove Emm flow support and move GIDSignIn strings to avoid repeated code. --- GoogleSignIn/Sources/GIDGoogleUser.m | 4 ---- GoogleSignIn/Sources/GIDSignIn.m | 8 -------- .../Implementations/GIDVerifyAccountDetail.m | 19 ++----------------- .../Sources/Public/GoogleSignIn/GIDSignIn.h | 8 ++++++++ 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index ec300839..466d7bef 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -43,10 +43,6 @@ static NSString *const kProfileDataKey = @"profileData"; static NSString *const kAuthStateKey = @"authState"; -// Parameters for the token exchange endpoint. -static NSString *const kAudienceParameter = @"audience"; -static NSString *const kOpenIDRealmParameter = @"openid.realm"; - // Additional parameter names for EMM. static NSString *const kEMMSupportParameterName = @"emm_support"; diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 8ad38645..6d82a713 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -124,14 +124,6 @@ // The delay before the new sign-in flow can be presented after the existing one is cancelled. static const NSTimeInterval kPresentationDelayAfterCancel = 1.0; -// Parameters for the auth and token exchange endpoints. -static NSString *const kAudienceParameter = @"audience"; -// See b/11669751 . -static NSString *const kOpenIDRealmParameter = @"openid.realm"; -static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; -static NSString *const kLoginHintParameter = @"login_hint"; -static NSString *const kHostedDomainParameter = @"hd"; - // Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 6bdae75f..96733983 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -20,7 +20,6 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" -#import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" @@ -47,15 +46,6 @@ // Expected path in the URL scheme to be handled. static NSString *const kBrowserCallbackPath = @"/oauth2callback"; -// The EMM support version -static NSString *const kEMMVersion = @"1"; - -// Parameters for the auth and token exchange endpoints. -static NSString *const kAudienceParameter = @"audience"; -static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; -static NSString *const kLoginHintParameter = @"login_hint"; -static NSString *const kHostedDomainParameter = @"hd"; - @implementation GIDVerifyAccountDetail { // AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; @@ -151,7 +141,7 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * kBrowserCallbackPath]]; NSMutableDictionary *additionalParameters = [@{} mutableCopy]; - additionalParameters[kIncludeGrantedScopesParameter] = @"true"; + additionalParameters[kIncludeGrantedScopesParameter] = @"false"; if (options.configuration.serverClientID) { additionalParameters[kAudienceParameter] = options.configuration.serverClientID; } @@ -161,11 +151,6 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * if (options.configuration.hostedDomain) { additionalParameters[kHostedDomainParameter] = options.configuration.hostedDomain; } - - [additionalParameters addEntriesFromDictionary: - [GIDEMMSupport parametersWithParameters:options.extraParams - emmSupport:kEMMVersion - isPasscodeInfoRequired:NO]]; additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); @@ -179,7 +164,7 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * // TODO(#405): Use request variable to present request and process response. __unused OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration clientId:options.configuration.clientID scopes:scopes redirectURL:redirectURL diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 2576b13d..15068513 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -29,6 +29,14 @@ NS_ASSUME_NONNULL_BEGIN +// Parameters for the auth and token exchange endpoints. +static NSString *const kAudienceParameter = @"audience"; +// See b/11669751 . +static NSString *const kOpenIDRealmParameter = @"openid.realm"; +static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; +static NSString *const kLoginHintParameter = @"login_hint"; +static NSString *const kHostedDomainParameter = @"hd"; + /// The error domain for `NSError`s returned by the Google Sign-In SDK. extern NSErrorDomain const kGIDSignInErrorDomain; From 51c5a368c1c43c9c850a0eb2b4975588305bed00 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 8 May 2024 16:30:06 -0700 Subject: [PATCH 20/55] Unblock testing in GIDVerifyAccountDetailTest by changing GIDSignInTest strict mocks to less restrictive. Also, fix nullability warnings in GIDFakeMainBundle. --- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 28 +++-- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 16 +-- GoogleSignIn/Tests/Unit/GIDSignInTest.m | 4 +- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 111 +++++++++--------- 4 files changed, 85 insertions(+), 74 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index 559cfbb7..cea717d6 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -22,11 +22,23 @@ */ @interface GIDFakeMainBundle : NSObject -- (instancetype)initWithClientID:(id)clientID - serverClientID:(id)serverClientID - hostedDomain:(id)hostedDomain - openIDRealm:(id)openIDRealm; +/** + * @fn initWithClientID:serverClientID:hostedDomain:openIDRealm: + * @brief Initializes a GIDFakeMainBundle object. + * @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. + */ +- (nullable instancetype)initWithClientID:(nullable id)clientID + serverClientID:(nullable id)serverClientID + hostedDomain:(nullable id)hostedDomain + openIDRealm:(nullable id)openIDRealm; +/** + * @fn startFaking: + * @brief Starts faking [NSBundle mainBundle] + */ - (void)startFaking; /** @@ -94,9 +106,9 @@ * @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; +- (void)fakeWithClientID:(nullable id)clientID + serverClientID:(nullable id)serverClientID + hostedDomain:(nullable id)hostedDomain + openIDRealm:(nullable id)openIDRealm; @end diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index e66c29df..c4d11a12 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -37,10 +37,10 @@ @implementation GIDFakeMainBundle { NSMutableDictionary *_fakeConfig; } -- (instancetype)initWithClientID:(id)clientID - serverClientID:(id)serverClientID - hostedDomain:(id)hostedDomain - openIDRealm:(id)openIDRealm { +- (nullable instancetype)initWithClientID:(nullable id)clientID + serverClientID:(nullable id)serverClientID + hostedDomain:(nullable id)hostedDomain + openIDRealm:(nullable id)openIDRealm { self = [super init]; if (self) { @@ -48,10 +48,10 @@ - (instancetype)initWithClientID:(id)clientID _fakeConfig = clientID ? [@{ @"GIDClientID" : clientID } mutableCopy] : [@{} mutableCopy]; - _fakeConfig[kConfigClientIDKey] = clientID; - _fakeConfig[kConfigServerClientIDKey] = serverClientID; - _fakeConfig[kConfigHostedDomainKey] = hostedDomain; - _fakeConfig[kConfigOpenIDRealmKey] = openIDRealm; + [self fakeWithClientID:clientID + serverClientID:serverClientID + hostedDomain:hostedDomain + openIDRealm:openIDRealm]; } return self; } diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index c64f1611..7fed4c13 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -286,12 +286,12 @@ - (void)setUp { #elif TARGET_OS_OSX _presentingWindow = OCMStrictClassMock([NSWindow class]); #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - _authState = OCMStrictClassMock([OIDAuthState class]); + _authState = OCMClassMock([OIDAuthState class]); OCMStub([_authState alloc]).andReturn(_authState); OCMStub([_authState initWithAuthorizationResponse:OCMOCK_ANY]).andReturn(_authState); _tokenResponse = OCMStrictClassMock([OIDTokenResponse class]); _tokenRequest = OCMStrictClassMock([OIDTokenRequest class]); - _authorization = OCMStrictClassMock([GTMAuthSession class]); + _authorization = OCMClassMock([GTMAuthSession class]); _keychainStore = OCMStrictClassMock([GTMKeychainStore class]); OCMStub( [_keychainStore retrieveAuthSessionWithItemName:OCMOCK_ANY error:OCMArg.anyObjectRef] diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index ea642f04..d1a2f772 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -25,11 +25,15 @@ #import "GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h" #import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" -#ifdef SWIFT_PACKAGE -@import OCMock; -#else -#import -#endif +// Exception Reasons +static NSString * const kSchemesNotSupportedExceptionReason = + @"Your app is missing support for the following URL schemes: fakeclientid"; +static NSString * const kClientIDMissingExceptionReason = + @"You must specify |clientID| in |GIDConfiguration|"; +static NSString * const kMissingCurrentUserExceptionReason = + @"|currentUser| must be set to verify."; +static NSString * const kMissingPresentingViewControllerExceptionReason = + @"|presentingViewController| must be set."; static NSString * const kClientId = @"FakeClientID"; static NSString * const kServerClientId = @"FakeServerClientID"; @@ -61,9 +65,8 @@ - (void)setUp { _verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; - GIDVerifiableAccountDetail *ageOver18Detail = [[GIDVerifiableAccountDetail alloc] - initWithAccountDetailType: - GIDAccountDetailTypeAgeOver18]; + GIDVerifiableAccountDetail *ageOver18Detail = + [[GIDVerifiableAccountDetail alloc] initWithAccountDetailType:GIDAccountDetailTypeAgeOver18]; _verifiableAccountDetails = @[ageOver18Detail]; _fakeMainBundle = [[GIDFakeMainBundle alloc] initWithClientID:kClientId @@ -72,7 +75,6 @@ - (void)setUp { openIDRealm:kOpenIDRealm]; } - #pragma mark - Tests - (void)testInit { @@ -112,7 +114,6 @@ - (void)testInit_invalidConfig { openIDRealm:nil]; [_fakeMainBundle startFaking]; - GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNil(verifyAccountDetail.configuration); } @@ -144,14 +145,16 @@ - (void)testCurrentUserException { #pragma GCC diagnostic pop OIDAuthState *authState = [OIDAuthState testInstance]; -// GIDSignIn.sharedInstance.currentUser = nil; - - XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil], - NSException, - NSInvalidArgumentException, - @"|currentUser| must be set to verify."); + GIDSignIn.sharedInstance.currentUser = nil; + + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + XCTAssertEqual(exception.name, NSInvalidArgumentException); + XCTAssertEqualObjects(exception.reason, kMissingCurrentUserExceptionReason); + } } - (void)testPresentingViewControllerException { @@ -162,23 +165,16 @@ - (void)testPresentingViewControllerException { _presentingViewController = nil; OIDAuthState *authState = [OIDAuthState testInstance]; -// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState -// profileData:nil]; - -// GIDSignIn *signIn = [[GIDSignIn alloc] initPrivate]; - id signIn = OCMClassMock([GIDSignIn class]); - OCMStub([signIn sharedInstance]).andReturn(signIn); - - GIDGoogleUser *currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState - profileData:nil]; - OCMStub([signIn currentUser]).andReturn(currentUser); - - XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil], - NSException, - NSInvalidArgumentException, - @"|presentingViewController| must be set."); + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + XCTAssertEqual(exception.name, NSInvalidArgumentException); + XCTAssertEqualObjects(exception.reason, kMissingPresentingViewControllerExceptionReason); + } } - (void)testClientIDMissingException { @@ -187,16 +183,18 @@ - (void)testClientIDMissingException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop -// OIDAuthState *authState = [OIDAuthState testInstance]; -// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState -// profileData:nil]; - - XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil], - NSException, - NSInvalidArgumentException, - @"You must specify |clientID| in |GIDConfiguration|"); + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + XCTAssertEqual(exception.name, NSInvalidArgumentException); + XCTAssertEqualObjects(exception.reason, kClientIDMissingExceptionReason); + } } - (void)testSchemesNotSupportedException { @@ -205,17 +203,18 @@ - (void)testSchemesNotSupportedException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:kClientId]; #pragma GCC diagnostic pop -// OIDAuthState *authState = [OIDAuthState testInstance]; -// GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState -// profileData:nil]; - - XCTAssertThrowsSpecificNamed([_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails - presentingViewController:_presentingViewController - completion:nil], - NSException, - NSInvalidArgumentException, - @"Your app is missing support for the following URL schemes: " - "fakeclientid"); + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDSignIn.sharedInstance.currentUser = [[GIDGoogleUser alloc] initWithAuthState:authState + profileData:nil]; + + @try { + [_verifyAccountDetail verifyAccountDetails:_verifiableAccountDetails + presentingViewController:_presentingViewController + completion:nil]; + } @catch (NSException *exception) { + XCTAssertEqual(exception.name, NSInvalidArgumentException); + XCTAssertEqualObjects(exception.reason, kSchemesNotSupportedExceptionReason); + } } @end From 6ce9f101fe2b7e95259acfee7671096f24f7e320 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 9 May 2024 14:02:46 -0700 Subject: [PATCH 21/55] Address formatting and indicate designated initializer in GIDFakeMainBundle. --- .../GoogleSignIn/GIDVerifyAccountDetail.h | 6 +++++- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h | 3 ++- GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m | 7 +++++++ GoogleSignIn/Tests/Unit/GIDSignInTest.m | 2 ++ .../Tests/Unit/GIDVerifyAccountDetailTest.m | 18 +++++++++++------- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 424124a2..a500c591 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -43,8 +43,12 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// The active configuration for this instance of `GIDVerifyAccountDetail`. @property(nonatomic, nullable) GIDConfiguration *configuration; +/// Initialize a `GIDVerifyAccountDetail` object by specifying all available properties. +/// +/// @param config The configuration to be used. +/// @return An initialized `GIDVerifyAccountDetail` instance. - (instancetype)initWithConfig:(nullable GIDConfiguration *)config -NS_DESIGNATED_INITIALIZER; + NS_DESIGNATED_INITIALIZER; /// Starts an interactive verification flow. /// diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h index cea717d6..d6039d8b 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.h @@ -33,7 +33,8 @@ - (nullable instancetype)initWithClientID:(nullable id)clientID serverClientID:(nullable id)serverClientID hostedDomain:(nullable id)hostedDomain - openIDRealm:(nullable id)openIDRealm; + openIDRealm:(nullable id)openIDRealm + NS_DESIGNATED_INITIALIZER; /** * @fn startFaking: diff --git a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m index c4d11a12..9f1843ae 100644 --- a/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m +++ b/GoogleSignIn/Tests/Unit/GIDFakeMainBundle.m @@ -56,6 +56,13 @@ - (nullable instancetype)initWithClientID:(nullable id)clientID return self; } +- (instancetype)init { + return [self initWithClientID:nil + serverClientID:nil + hostedDomain:nil + openIDRealm:nil]; +} + - (void)startFaking { _fakedKeys = @[ kCFBundleURLTypesKey, kConfigClientIDKey, diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index 7fed4c13..537375d0 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInTest.m @@ -286,6 +286,8 @@ - (void)setUp { #elif TARGET_OS_OSX _presentingWindow = OCMStrictClassMock([NSWindow class]); #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + + // TODO: Fix strict mocks from carrying forward to subsequent tests. (#410) _authState = OCMClassMock([OIDAuthState class]); OCMStub([_authState alloc]).andReturn(_authState); OCMStub([_authState initWithAuthorizationResponse:OCMOCK_ANY]).andReturn(_authState); diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index d1a2f772..b980d260 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -41,16 +41,16 @@ static NSString * const kFakeHostedDomain = @"fakehosteddomain.com"; @interface GIDVerifyAccountDetailTests : XCTestCase -// The |UIViewController| object being tested. +/// The |UIViewController| object being tested. @property UIViewController *presentingViewController; -// Fake [NSBundle mainBundle]. +/// Fake [NSBundle mainBundle]. @property GIDFakeMainBundle *fakeMainBundle; -// The |GIDVerifyAccountDetail| object being tested. +/// The |GIDVerifyAccountDetail| object being tested. @property GIDVerifyAccountDetail *verifyAccountDetail; -// The list of account details when testing [GIDVerifiableAccountDetail]. +/// The list of account details when testing [GIDVerifiableAccountDetail]. @property NSArray *verifiableAccountDetails; @end @@ -75,6 +75,11 @@ - (void)setUp { openIDRealm:kOpenIDRealm]; } +- (void)tearDown { + [_fakeMainBundle stopFaking]; + [super tearDown]; +} + #pragma mark - Tests - (void)testInit { @@ -129,8 +134,8 @@ - (void)testInitWithConfig_fullConfig { hostedDomain:kFakeHostedDomain openIDRealm:kOpenIDRealm]; - GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] - initWithConfig:configuration]; + GIDVerifyAccountDetail *verifyAccountDetail = + [[GIDVerifyAccountDetail alloc] initWithConfig:configuration]; XCTAssertNotNil(verifyAccountDetail.configuration); XCTAssertEqual(verifyAccountDetail.configuration.clientID, kClientId); XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); @@ -144,7 +149,6 @@ - (void)testCurrentUserException { _verifyAccountDetail.configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - OIDAuthState *authState = [OIDAuthState testInstance]; GIDSignIn.sharedInstance.currentUser = nil; @try { From 4d981eb5b69c4756a5eb01023e59932ee8fb56eb Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 9 May 2024 14:42:49 -0700 Subject: [PATCH 22/55] Add stopFaking calls in appropriate tests. --- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index b980d260..5bc43bd7 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -75,11 +75,6 @@ - (void)setUp { openIDRealm:kOpenIDRealm]; } -- (void)tearDown { - [_fakeMainBundle stopFaking]; - [super tearDown]; -} - #pragma mark - Tests - (void)testInit { @@ -91,6 +86,8 @@ - (void)testInit { XCTAssertNil(verifyAccountDetail.configuration.serverClientID); XCTAssertNil(verifyAccountDetail.configuration.hostedDomain); XCTAssertNil(verifyAccountDetail.configuration.openIDRealm); + + [_fakeMainBundle stopFaking]; } - (void)testInit_noConfig { @@ -98,6 +95,8 @@ - (void)testInit_noConfig { GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNil(verifyAccountDetail.configuration); + + [_fakeMainBundle stopFaking]; } @@ -110,6 +109,8 @@ - (void)testInit_fullConfig { XCTAssertEqual(verifyAccountDetail.configuration.serverClientID, kServerClientId); XCTAssertEqual(verifyAccountDetail.configuration.hostedDomain, kFakeHostedDomain); XCTAssertEqual(verifyAccountDetail.configuration.openIDRealm, kOpenIDRealm); + + [_fakeMainBundle stopFaking]; } - (void)testInit_invalidConfig { @@ -121,6 +122,8 @@ - (void)testInit_invalidConfig { GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] init]; XCTAssertNil(verifyAccountDetail.configuration); + + [_fakeMainBundle stopFaking]; } - (void)testInitWithConfig_noConfig { From b744a4bc4d42bb0f4b3a145b1f9a042ddbe07323 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 9 May 2024 15:21:15 -0700 Subject: [PATCH 23/55] Fix indentation and remove parameter from `additionalParameters`. --- .../Implementations/GIDVerifyAccountDetail.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 96733983..90dd527a 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -141,7 +141,6 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * kBrowserCallbackPath]]; NSMutableDictionary *additionalParameters = [@{} mutableCopy]; - additionalParameters[kIncludeGrantedScopesParameter] = @"false"; if (options.configuration.serverClientID) { additionalParameters[kAudienceParameter] = options.configuration.serverClientID; } @@ -164,12 +163,12 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * // TODO(#405): Use request variable to present request and process response. __unused OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration - clientId:options.configuration.clientID - scopes:scopes - redirectURL:redirectURL - responseType:OIDResponseTypeCode - additionalParameters:additionalParameters]; + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + clientId:options.configuration.clientID + scopes:scopes + redirectURL:redirectURL + responseType:OIDResponseTypeCode + additionalParameters:additionalParameters]; } #pragma mark - Helpers From 89b92d3674e8a02be1258ea07503dcc2395d7291 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 10 May 2024 15:12:49 -0700 Subject: [PATCH 24/55] Let parameter-less `init` be nullable and require `initWithConfig` to pass a configuration. --- .../Implementations/GIDVerifyAccountDetail.m | 8 ++++++-- .../Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h | 2 +- GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m | 5 ----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 72b9bc83..8761c52c 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -27,7 +27,7 @@ @implementation GIDVerifyAccountDetail -- (instancetype)initWithConfig:(nullable GIDConfiguration *)configuration { +- (instancetype)initWithConfig:(GIDConfiguration *)configuration { self = [super init]; if (self) { _configuration = configuration; @@ -35,13 +35,17 @@ - (instancetype)initWithConfig:(nullable GIDConfiguration *)configuration { return self; } -- (instancetype)init { +- (nullable instancetype)init { GIDConfiguration *configuration; NSBundle *bundle = NSBundle.mainBundle; if (bundle) { configuration = [GIDConfiguration configurationFromBundle:bundle]; } + if (!configuration) { + return nil; + } + return [self initWithConfig:configuration]; } diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index a500c591..c623a28c 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -47,7 +47,7 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// /// @param config The configuration to be used. /// @return An initialized `GIDVerifyAccountDetail` instance. -- (instancetype)initWithConfig:(nullable GIDConfiguration *)config +- (instancetype)initWithConfig:(GIDConfiguration *)config NS_DESIGNATED_INITIALIZER; /// Starts an interactive verification flow. diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 5bc43bd7..a9ea0369 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -126,11 +126,6 @@ - (void)testInit_invalidConfig { [_fakeMainBundle stopFaking]; } -- (void)testInitWithConfig_noConfig { - GIDVerifyAccountDetail *verifyAccountDetail = [[GIDVerifyAccountDetail alloc] initWithConfig:nil]; - XCTAssertNil(verifyAccountDetail.configuration); -} - - (void)testInitWithConfig_fullConfig { GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:kClientId serverClientID:kServerClientId From 78daa0b1475bea2bae8d10f0dcba1f5f8183753a Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 10 May 2024 16:21:40 -0700 Subject: [PATCH 25/55] Create `GIDSignInConstants` class to hold common constants across the sign-in and verify flow. --- GoogleSignIn/Sources/GIDGoogleUser.m | 1 + GoogleSignIn/Sources/GIDSignIn.m | 1 + GoogleSignIn/Sources/GIDSignInConstants.h | 25 +++++++++++++++++ GoogleSignIn/Sources/GIDSignInConstants.m | 27 +++++++++++++++++++ .../Implementations/GIDVerifyAccountDetail.m | 1 + .../Sources/Public/GoogleSignIn/GIDSignIn.h | 8 ------ 6 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 GoogleSignIn/Sources/GIDSignInConstants.h create mode 100644 GoogleSignIn/Sources/GIDSignInConstants.m diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 466d7bef..0ec2738c 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -23,6 +23,7 @@ #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" #import "GoogleSignIn/Sources/GIDSignIn_Private.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDToken_Private.h" diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 6d82a713..be35b604 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -22,6 +22,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignInResult.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDCallbackQueue.h" diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h new file mode 100644 index 00000000..a1cb17ad --- /dev/null +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// Parameters for the auth and token exchange endpoints. +extern NSString *const kAudienceParameter; +// See b/11669751 . +extern NSString *const kOpenIDRealmParameter; +extern NSString *const kIncludeGrantedScopesParameter; +extern NSString *const kLoginHintParameter; +extern NSString *const kHostedDomainParameter; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m new file mode 100644 index 00000000..7c7fb300 --- /dev/null +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleSignIn/Sources/GIDSignInConstants.h" + +// Parameters for the auth and token exchange endpoints. +NSString *const kAudienceParameter = @"audience"; +// See b/11669751 . +NSString *const kOpenIDRealmParameter = @"openid.realm"; +NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; +NSString *const kLoginHintParameter = @"login_hint"; +NSString *const kHostedDomainParameter = @"hd"; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 90dd527a..5a7740c0 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -22,6 +22,7 @@ #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" @import GTMAppAuth; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 15068513..2576b13d 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -29,14 +29,6 @@ NS_ASSUME_NONNULL_BEGIN -// Parameters for the auth and token exchange endpoints. -static NSString *const kAudienceParameter = @"audience"; -// See b/11669751 . -static NSString *const kOpenIDRealmParameter = @"openid.realm"; -static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; -static NSString *const kLoginHintParameter = @"login_hint"; -static NSString *const kHostedDomainParameter = @"hd"; - /// The error domain for `NSError`s returned by the Google Sign-In SDK. extern NSErrorDomain const kGIDSignInErrorDomain; From 7112ce5b86a8573260679468d4bab4cd078470ac Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 10 May 2024 16:36:28 -0700 Subject: [PATCH 26/55] Fix method description and make `initWithConfig` nullable. --- .../Implementations/GIDVerifyAccountDetail.m | 2 +- .../Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 8761c52c..152d90a5 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -27,7 +27,7 @@ @implementation GIDVerifyAccountDetail -- (instancetype)initWithConfig:(GIDConfiguration *)configuration { +- (nullable instancetype)initWithConfig:(GIDConfiguration *)configuration { self = [super init]; if (self) { _configuration = configuration; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index c623a28c..c2c57c05 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -47,7 +47,8 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve /// /// @param config The configuration to be used. /// @return An initialized `GIDVerifyAccountDetail` instance. -- (instancetype)initWithConfig:(GIDConfiguration *)config +/// Otherwise, `nil` if the configuration is invalid or the initializer fails. +- (nullable instancetype)initWithConfig:(GIDConfiguration *)config NS_DESIGNATED_INITIALIZER; /// Starts an interactive verification flow. From 2023dbb84e94df7f31319d82486aa5ff42ac7a0b Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 13 May 2024 10:48:12 -0700 Subject: [PATCH 27/55] Fix formatting and add `openIDRealm` param. --- .../Implementations/GIDVerifyAccountDetail.m | 96 ++++++------------- 1 file changed, 28 insertions(+), 68 deletions(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 9b6f61d3..8041170c 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -26,9 +26,6 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDCallbackQueue.h" -#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" - -//#import "GoogleSignIn/Sources/GIDProfileData_Private.h" @import GTMAppAuth; @@ -54,25 +51,15 @@ // Expected path in the URL scheme to be handled. static NSString *const kBrowserCallbackPath = @"/oauth2callback"; -// The EMM support version -static NSString *const kEMMVersion = @"1"; - // The error code for Google Identity. NSErrorDomain const kGIDVerifyErrorDomain = @"com.google.GIDVerify"; // Error string for user cancelations. -static NSString *const kUserCanceledError = @"The user canceled the sign-in flow."; +static NSString *const kUserCanceledError = @"The user canceled the verification flow."; // Parameters in the callback URL coming back from browser. static NSString *const kOAuth2ErrorKeyName = @"error"; static NSString *const kOAuth2AccessDenied = @"access_denied"; -static NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; - -// Parameters for the auth and token exchange endpoints. -static NSString *const kAudienceParameter = @"audience"; -static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; -static NSString *const kLoginHintParameter = @"login_hint"; -static NSString *const kHostedDomainParameter = @"hd"; // Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; @@ -82,7 +69,6 @@ @interface GIDVerifyAuthFlow : GIDCallbackQueue @property(nonatomic, strong, nullable) OIDAuthState *authState; @property(nonatomic, strong, nullable) NSError *error; -@property(nonatomic, copy, nullable) NSString *emmSupport; @property(nonatomic, nullable) GIDProfileData *profileData; @end @@ -107,8 +93,8 @@ - (nullable instancetype)initWithConfig:(GIDConfiguration *)configuration { NSString *tokenEndpointURL = [NSString stringWithFormat:kTokenURLTemplate, [GIDSignInPreferences googleTokenServer]]; _appAuthConfiguration = [[OIDServiceConfiguration alloc] - initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] - tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; + initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] + tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; } return self; } @@ -203,10 +189,6 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * additionalParameters[kHostedDomainParameter] = options.configuration.hostedDomain; } - [additionalParameters addEntriesFromDictionary: - [GIDEMMSupport parametersWithParameters:options.extraParams - emmSupport:kEMMVersion - isPasscodeInfoRequired:NO]]; additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); @@ -219,33 +201,31 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * } OIDAuthorizationRequest *request = - [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration - clientId:options.configuration.clientID - scopes:scopes - redirectURL:redirectURL - responseType:OIDResponseTypeCode - additionalParameters:additionalParameters]; + [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration + clientId:options.configuration.clientID + scopes:scopes + redirectURL:redirectURL + responseType:OIDResponseTypeCode + additionalParameters:additionalParameters]; _currentAuthorizationFlow = [OIDAuthorizationService - presentAuthorizationRequest:request - presentingViewController:options.presentingViewController - callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, - NSError *_Nullable error) { - [self processAuthorizationResponse:authorizationResponse - error:error - emmSupport:kEMMVersion]; + presentAuthorizationRequest:request + presentingViewController:options.presentingViewController + callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, + NSError *_Nullable error) { + [self processAuthorizationResponse:authorizationResponse + error:error]; }]; } - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse - error:(NSError *)error - emmSupport:(NSString *)emmSupport{ + error:(NSError *)error { GIDVerifyAuthFlow *authFlow = [[GIDVerifyAuthFlow alloc] init]; - authFlow.emmSupport = emmSupport; if (authorizationResponse) { if (authorizationResponse.authorizationCode.length) { - authFlow.authState = [[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse]; + authFlow.authState = + [[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse]; // perform auth code exchange [self maybeFetchToken:authFlow]; } else { @@ -254,15 +234,6 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; NSDictionary *params = authorizationResponse.additionalParameters; - if (authFlow.emmSupport) { - [authFlow wait]; - BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] handleErrorFromResponse:params completion:^{ - [authFlow next]; - }]; - if (isEMMError) { - errorCode = kGIDVerifyErrorCodeEMM; - } - } errorString = (NSString *)params[kOAuth2ErrorKeyName]; if ([errorString isEqualToString:kOAuth2AccessDenied]) { errorCode = kGIDVerifyErrorCodeCanceled; @@ -280,7 +251,7 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe authFlow.error = [self errorWithString:errorString code:errorCode]; } - // completion and decode + // TODO: Add completion callback method (#413). } // Fetches the access token if necessary as part of the auth flow. @@ -297,13 +268,9 @@ - (void)maybeFetchToken:(GIDVerifyAuthFlow *)authFlow { if (_configuration.serverClientID) { additionalParameters[kAudienceParameter] = _configuration.serverClientID; } - NSDictionary *params = - authState.lastAuthorizationResponse.additionalParameters; - NSString *passcodeInfoRequired = (NSString *)params[kEMMPasscodeInfoRequiredKeyName]; - [additionalParameters addEntriesFromDictionary: - [GIDEMMSupport parametersWithParameters:@{} - emmSupport:authFlow.emmSupport - isPasscodeInfoRequired:passcodeInfoRequired.length > 0]]; + if (_configuration.openIDRealm) { + additionalParameters[kOpenIDRealmParameter] = _configuration.openIDRealm; + } additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); @@ -311,29 +278,22 @@ - (void)maybeFetchToken:(GIDVerifyAuthFlow *)authFlow { if (!authState.lastTokenResponse.accessToken && authState.lastAuthorizationResponse.authorizationCode) { tokenRequest = [authState.lastAuthorizationResponse - tokenExchangeRequestWithAdditionalParameters:additionalParameters]; + tokenExchangeRequestWithAdditionalParameters:additionalParameters]; } else { [additionalParameters - addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; + addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; } [authFlow wait]; [OIDAuthorizationService - performTokenRequest:tokenRequest - callback:^(OIDTokenResponse *_Nullable tokenResponse, - NSError *_Nullable error) { + performTokenRequest:tokenRequest + callback:^(OIDTokenResponse *_Nullable tokenResponse, + NSError *_Nullable error) { [authState updateWithTokenResponse:tokenResponse error:error]; authFlow.error = error; - if (authFlow.emmSupport) { - [GIDEMMSupport handleTokenFetchEMMError:error completion:^(NSError *error) { - authFlow.error = error; - [authFlow next]; - }]; - } else { - [authFlow next]; - } + [authFlow next]; }]; } From 52429b724f32794a79b02cb547b52bc8e9a97089 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 13 May 2024 13:04:27 -0700 Subject: [PATCH 28/55] Add missing AppAuth/OID imports. --- .../Implementations/GIDVerifyAccountDetail.m | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 8041170c..3050409e 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -35,9 +35,19 @@ #else #import #import +#import +#import +#import +#import #import #import -#import +#import +#import + +#if TARGET_OS_IOS +#import +#endif + #endif #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST From aac80b45d224a16cedc1eafc61e71a9333ba0537 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 14 May 2024 14:15:32 -0700 Subject: [PATCH 29/55] Move constants to `GIDSignInConstants` and update doc comments. --- GoogleSignIn/Sources/GIDSignIn.m | 9 --------- GoogleSignIn/Sources/GIDSignInConstants.h | 20 +++++++++++++++++-- GoogleSignIn/Sources/GIDSignInConstants.m | 8 +++++++- .../Implementations/GIDVerifyAccountDetail.m | 20 ++++++------------- .../GoogleSignIn/GIDVerifyAccountDetail.h | 4 ++-- .../Tests/Unit/GIDVerifyAccountDetailTest.m | 4 ++-- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index be35b604..0452b24f 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -70,21 +70,12 @@ // The name of the query parameter used for logging the restart of auth from EMM callback. static NSString *const kEMMRestartAuthParameter = @"emmres"; -// The URL template for the authorization endpoint. -static NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; - -// The URL template for the token endpoint. -static NSString *const kTokenURLTemplate = @"https://%@/token"; - // The URL template for the URL to get user info. static NSString *const kUserInfoURLTemplate = @"https://%@/oauth2/v3/userinfo?access_token=%@"; // The URL template for the URL to revoke the token. static NSString *const kRevokeTokenURLTemplate = @"https://%@/o/oauth2/revoke?token=%@"; -// Expected path in the URL scheme to be handled. -static NSString *const kBrowserCallbackPath = @"/oauth2callback"; - // Expected path for EMM callback. static NSString *const kEMMCallbackPath = @"/emmcallback"; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h index a1cb17ad..e04db0fa 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.h +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -16,10 +16,26 @@ #import -// Parameters for the auth and token exchange endpoints. +/// The URL template for the authorization endpoint. +extern NSString *const kAuthorizationURLTemplate; + +/// The URL template for the token endpoint. +extern NSString *const kTokenURLTemplate; + +/// Expected path in the URL scheme to be handled. +extern NSString *const kBrowserCallbackPath; + +/// The name of the audience parameter for the auth and token exchange endpoints. extern NSString *const kAudienceParameter; -// See b/11669751 . + +/// The name of the open ID realm parameter for the auth and token exchange endpoints. extern NSString *const kOpenIDRealmParameter; + +/// The name of the include granted scopes parameter for the auth and token exchange endpoints. extern NSString *const kIncludeGrantedScopesParameter; + +/// The name of the login hint parameter for the auth and token exchange endpoints. extern NSString *const kLoginHintParameter; + +/// The name of the hosted domain parameter for the auth and token exchange endpoints. extern NSString *const kHostedDomainParameter; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m index 7c7fb300..e8055428 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.m +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -18,9 +18,15 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" +// The URL templates for the authorization and token endpoints. +NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; +NSString *const kTokenURLTemplate = @"https://%@/token"; + +// Expected path in the URL scheme to be handled. +NSString *const kBrowserCallbackPath = @"/oauth2callback"; + // Parameters for the auth and token exchange endpoints. NSString *const kAudienceParameter = @"audience"; -// See b/11669751 . NSString *const kOpenIDRealmParameter = @"openid.realm"; NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; NSString *const kLoginHintParameter = @"login_hint"; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index cac3bb09..21c624bc 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -38,17 +38,8 @@ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -// The URL template for the authorization endpoint. -static NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; - -// The URL template for the token endpoint. -static NSString *const kTokenURLTemplate = @"https://%@/token"; - -// Expected path in the URL scheme to be handled. -static NSString *const kBrowserCallbackPath = @"/oauth2callback"; - @implementation GIDVerifyAccountDetail { - // AppAuth configuration object. + /// AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; } @@ -135,7 +126,7 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * // If the application does not support the required URL schemes tell the developer so. GIDSignInCallbackSchemes *schemes = - [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; + [[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID]; NSArray *unsupportedSchemes = [schemes unsupportedSchemes]; if (unsupportedSchemes.count != 0) { // NOLINTNEXTLINE(google-objc-avoid-throwing-exception) @@ -143,9 +134,10 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * format:@"Your app is missing support for the following URL schemes: %@", [unsupportedSchemes componentsJoinedByString:@", "]]; } - NSURL *redirectURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@:%@", - [schemes clientIdentifierScheme], - kBrowserCallbackPath]]; + NSString *redirectURI = [NSString stringWithFormat:@"%@:%@", + [schemes clientIdentifierScheme], + kBrowserCallbackPath]; + NSURL *redirectURL = [NSURL URLWithString:redirectURI]; NSMutableDictionary *additionalParameters = [@{} mutableCopy]; if (options.configuration.serverClientID) { diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 6fb68b24..3eb2dea8 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -16,7 +16,7 @@ #import -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import @@ -91,4 +91,4 @@ typedef void (^GIDVerifyCompletion)(GIDVerifiedAccountDetailResult *_Nullable ve NS_ASSUME_NONNULL_END -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m index 5b6d92a5..a5efdfff 100644 --- a/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m +++ b/GoogleSignIn/Tests/Unit/GIDVerifyAccountDetailTest.m @@ -14,7 +14,7 @@ #import -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" @@ -223,4 +223,4 @@ - (void)testSchemesNotSupportedException { @end -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST From 298d9c4f365cb8559cdc8ff68e50d0248cb42165 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 14 May 2024 14:25:46 -0700 Subject: [PATCH 30/55] Update preprocessor directives to exclude TARGET_OS_MACCATALYST. --- GoogleSignIn/Sources/GIDSignInInternalOptions.h | 16 ++++++++-------- GoogleSignIn/Sources/GIDSignInInternalOptions.m | 4 ++-- .../Tests/Unit/GIDSignInInternalOptionsTest.m | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.h b/GoogleSignIn/Sources/GIDSignInInternalOptions.h index c722d5d4..7a36e210 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.h +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.h @@ -24,9 +24,9 @@ #import "GoogleSignIn/Sources/GIDSignIn_Private.h" -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @class GIDConfiguration; @class GIDSignInResult; @@ -45,10 +45,10 @@ NS_ASSUME_NONNULL_BEGIN /// Whether the sign-in is an addScopes flow. NO means it is a sign in flow. @property(nonatomic, readonly) BOOL addScopesFlow; -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The user account details the Verify with Google flow will verify @property(nonatomic, copy, nullable, readonly) NSArray *accountDetailsToVerify; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The extra parameters used in the sign-in URL. @property(nonatomic, readonly, nullable) NSDictionary *extraParams; @@ -67,10 +67,10 @@ NS_ASSUME_NONNULL_BEGIN /// The completion block to be called at the completion of the flow. @property(nonatomic, readonly, nullable) GIDSignInCompletion completion; -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The completion block to be called at the completion of the verify flow. @property(nonatomic, readonly, nullable) GIDVerifyCompletion verifyCompletion; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST /// The scopes to be used during the flow. @property(nonatomic, copy, nullable) NSArray *scopes; @@ -79,14 +79,14 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy, nullable) NSString *loginHint; /// Creates the default options. -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint addScopesFlow:(BOOL)addScopesFlow accountDetailsToVerify:(NSArray *)accountDetailsToVerify verifyCompletion:(nullable GIDVerifyCompletion)completion; -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST #if TARGET_OS_IOS || TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration diff --git a/GoogleSignIn/Sources/GIDSignInInternalOptions.m b/GoogleSignIn/Sources/GIDSignInInternalOptions.m index f505eadf..74b271bd 100644 --- a/GoogleSignIn/Sources/GIDSignInInternalOptions.m +++ b/GoogleSignIn/Sources/GIDSignInInternalOptions.m @@ -26,7 +26,7 @@ @implementation GIDSignInInternalOptions -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration presentingViewController:(nullable UIViewController *)presentingViewController loginHint:(nullable NSString *)loginHint @@ -46,7 +46,7 @@ + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)con } return options; } -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST #if TARGET_OS_IOS || TARGET_OS_MACCATALYST + (instancetype)defaultOptionsWithConfiguration:(nullable GIDConfiguration *)configuration diff --git a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m index ac7d47e4..3c2e7fee 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m +++ b/GoogleSignIn/Tests/Unit/GIDSignInInternalOptionsTest.m @@ -33,7 +33,7 @@ @interface GIDSignInInternalOptionsTest : XCTestCase @implementation GIDSignInInternalOptionsTest -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)testDefaultOptionsForVerificationFlow { GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:kClientId serverClientID:nil @@ -59,7 +59,7 @@ - (void)testDefaultOptionsForVerificationFlow { XCTAssertEqual(options.presentingViewController, presentingViewController); XCTAssertEqual(options.accountDetailsToVerify, accountDetailsToVerify); } -#endif // TARGET_OS_IOS +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)testDefaultOptions { id configuration = OCMStrictClassMock([GIDConfiguration class]); From d220aa72c9203d6fef63c4ede647f50223d14064 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 15 May 2024 02:21:10 -0700 Subject: [PATCH 31/55] Move `GIDVerifyAuthFlow` into separate files and change integer values in `GIDVerifyCode` to positive. --- .../Implementations/GIDVerifyAccountDetail.m | 26 ++++-------- .../Implementations/GIDVerifyAuthFlow.h | 41 +++++++++++++++++++ .../GoogleSignIn/GIDVerifyAccountDetail.h | 6 +-- 3 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 3050409e..457a7585 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -19,13 +19,13 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" + +#import "GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -#import "GoogleSignIn/Sources/GIDCallbackQueue.h" @import GTMAppAuth; @@ -74,18 +74,6 @@ // Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; -// The callback queue used for authentication flow. -@interface GIDVerifyAuthFlow : GIDCallbackQueue - -@property(nonatomic, strong, nullable) OIDAuthState *authState; -@property(nonatomic, strong, nullable) NSError *error; -@property(nonatomic, nullable) GIDProfileData *profileData; - -@end - -@implementation GIDVerifyAuthFlow -@end - @implementation GIDVerifyAccountDetail { // AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; @@ -98,10 +86,11 @@ - (nullable instancetype)initWithConfig:(GIDConfiguration *)configuration { if (self) { _configuration = configuration; - NSString *authorizationEndpointURL = [NSString stringWithFormat:kAuthorizationURLTemplate, - [GIDSignInPreferences googleAuthorizationServer]]; - NSString *tokenEndpointURL = [NSString stringWithFormat:kTokenURLTemplate, - [GIDSignInPreferences googleTokenServer]]; + NSString *authorizationEndpointURL = + [NSString stringWithFormat:kAuthorizationURLTemplate, + [GIDSignInPreferences googleAuthorizationServer]]; + NSString *tokenEndpointURL = + [NSString stringWithFormat:kTokenURLTemplate, [GIDSignInPreferences googleTokenServer]]; _appAuthConfiguration = [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:[NSURL URLWithString:authorizationEndpointURL] tokenEndpoint:[NSURL URLWithString:tokenEndpointURL]]; @@ -264,7 +253,6 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe // TODO: Add completion callback method (#413). } -// Fetches the access token if necessary as part of the auth flow. - (void)maybeFetchToken:(GIDVerifyAuthFlow *)authFlow { OIDAuthState *authState = authFlow.authState; // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h new file mode 100644 index 00000000..94966339 --- /dev/null +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/GIDCallbackQueue.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" + +@import GTMAppAuth; + +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GTMSessionFetcherCore; +#else +#import +#endif + +/// The callback queue used for authentication flow. +@interface GIDVerifyAuthFlow : GIDCallbackQueue + +/// A representation of the state of the OAuth session for this instance. +@property(nonatomic, strong, nullable) OIDAuthState *authState; + +/// The error thrown from the OAuth session encountered for this instance. +@property(nonatomic, strong, nullable) NSError *error; + +@end + +@implementation GIDVerifyAuthFlow +@end diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index bf3b1c09..56c023fe 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -38,11 +38,9 @@ extern NSErrorDomain const kGIDVerifyErrorDomain; /// A list of potential error codes returned from the Google Sign-In SDK. typedef NS_ERROR_ENUM(kGIDVerifyErrorDomain, GIDVerifyErrorCode) { /// Indicates an unknown error has occurred. - kGIDVerifyErrorCodeUnknown = -1, + kGIDVerifyErrorCodeUnknown = 1, /// Indicates the user canceled the verification request. - kGIDVerifyErrorCodeCanceled = -2, - /// Indicates an Enterprise Mobility Management related error has occurred. - kGIDVerifyErrorCodeEMM = -3, + kGIDVerifyErrorCodeCanceled = 2, }; /// Represents a completion block that takes a `GIDVerifiedAccountDetailResult` on success or an From 227f3e375f0a45edd1681463eb8c18e189fab8e4 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 15 May 2024 02:39:33 -0700 Subject: [PATCH 32/55] Fix formatting. --- GoogleSignIn/Sources/GIDSignInConstants.m | 4 ---- .../Implementations/GIDVerifyAccountDetail.m | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m index e8055428..bb90d37a 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.m +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -18,14 +18,10 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" -// The URL templates for the authorization and token endpoints. NSString *const kAuthorizationURLTemplate = @"https://%@/o/oauth2/v2/auth"; NSString *const kTokenURLTemplate = @"https://%@/token"; - -// Expected path in the URL scheme to be handled. NSString *const kBrowserCallbackPath = @"/oauth2callback"; -// Parameters for the auth and token exchange endpoints. NSString *const kAudienceParameter = @"audience"; NSString *const kOpenIDRealmParameter = @"openid.realm"; NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 21c624bc..7e192768 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -134,9 +134,8 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * format:@"Your app is missing support for the following URL schemes: %@", [unsupportedSchemes componentsJoinedByString:@", "]]; } - NSString *redirectURI = [NSString stringWithFormat:@"%@:%@", - [schemes clientIdentifierScheme], - kBrowserCallbackPath]; + NSString *redirectURI = + [NSString stringWithFormat:@"%@:%@", [schemes clientIdentifierScheme], kBrowserCallbackPath]; NSURL *redirectURL = [NSURL URLWithString:redirectURI]; NSMutableDictionary *additionalParameters = [@{} mutableCopy]; From 02e047a894599b2ee36bc1ce90a545a16da718e8 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 17 May 2024 15:57:04 -0700 Subject: [PATCH 33/55] Create `GIDAuthFlow` class to group properties in authentication flow. --- GoogleSignIn/Sources/GIDAuthFlow.h | 38 ++++++++++++++++++++++++++++++ GoogleSignIn/Sources/GIDAuthFlow.m | 19 +++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 GoogleSignIn/Sources/GIDAuthFlow.h create mode 100644 GoogleSignIn/Sources/GIDAuthFlow.m diff --git a/GoogleSignIn/Sources/GIDAuthFlow.h b/GoogleSignIn/Sources/GIDAuthFlow.h new file mode 100644 index 00000000..3feb087e --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthFlow.h @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleSignIn/Sources/GIDCallbackQueue.h" + +@class OIDAuthState; +@class GIDProfileData; + +/// The callback queue used for authentication flow. +@interface GIDAuthFlow : GIDCallbackQueue + +/// A representation of the state of the OAuth session for this instance. +@property(nonatomic, strong, nullable) OIDAuthState *authState; + +/// The error thrown from the OAuth session encountered for this instance. +@property(nonatomic, strong, nullable) NSError *error; + +@property(nonatomic, copy, nullable) NSString *emmSupport; +@property(nonatomic, nullable) GIDProfileData *profileData; + + + +@end diff --git a/GoogleSignIn/Sources/GIDAuthFlow.m b/GoogleSignIn/Sources/GIDAuthFlow.m new file mode 100644 index 00000000..587ff717 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthFlow.m @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import "GoogleSignIn/Sources/GIDAuthFlow.h" + +@implementation GIDAuthFlow +@end From f42581b72e5b2ba8c77808910731f989b1622576 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 17 May 2024 15:59:00 -0700 Subject: [PATCH 34/55] Create class `GIDAuthorizationResponseHelper` to process authorization response in sign-in and verify flow. --- .../Sources/GIDAuthorizationResponseHelper.h | 45 ++++ .../Sources/GIDAuthorizationResponseHelper.m | 242 ++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h new file mode 100644 index 00000000..f0e87dd9 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class GIDAuthFlow; +@class GIDConfiguration; +@class OIDAuthorizationResponse; + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, GIDFlowName) { + SignIn, + Verify, +}; + +@interface GIDAuthorizationResponseHelper : NSObject + +@property(nonatomic, strong, nullable) GIDConfiguration *configuration; + +- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authFlow + emmSupport:emmSupport + flowName:(GIDFlowName)flowName + configuration:(GIDConfiguration *)config; + +- (GIDAuthFlow *)processWithError:(NSError *)error; + +- (void)maybeFetchToken:(GIDAuthFlow *)authFlow; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m new file mode 100644 index 00000000..22dfb404 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -0,0 +1,242 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" + +#import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDEMMSupport.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" +#import "GoogleSignIn/Sources/GIDSignInPreferences.h" + +#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" + + +@import GTMAppAuth; + +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +// Error string for user cancelations. +static NSString *const kUserCanceledSignInError = @"The user canceled the sign-in flow."; +static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; + + +static NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; + +// Minimum time to expiration for a restored access token. +static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; + +@implementation GIDAuthorizationResponseHelper { + OIDAuthorizationResponse *_authorizationResponse; + NSString *_emmSupport; + GIDFlowName _flowName; +} + +- (instancetype) + initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + emmSupport:(NSString *)emmSupport + flowName:(GIDFlowName)flowName + configuration:(GIDConfiguration *)configuration { + self = [super init]; + if (self) { + _authorizationResponse = authorizationResponse; + _emmSupport = emmSupport; + _flowName = flowName; + _configuration = configuration; + } +} + +- (GIDAuthFlow *)processWithError:(NSError *)error { + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; + authFlow.emmSupport = _emmSupport; + + if (_authorizationResponse) { + if (_authorizationResponse.authorizationCode.length) { + authFlow.authState = + [[OIDAuthState alloc] initWithAuthorizationResponse:_authorizationResponse]; + [self maybeFetchToken:authFlow]; + } else { + [self authorizationCodeErrorWithAuthFlow:authFlow]; + } + } else { + [self authorizationResponseErrorWithAuthFlow:authFlow + error:error]; + } + return authFlow; +} + +// Fetches the access token if necessary as part of the auth flow. +- (void)maybeFetchToken:(GIDAuthFlow *)authFlow { + OIDAuthState *authState = authFlow.authState; + // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. + if (authFlow.error || + (authState.lastTokenResponse.accessToken && + [authState.lastTokenResponse.accessTokenExpirationDate timeIntervalSinceNow] > + kMinimumRestoredAccessTokenTimeToExpire)) { + return; + } + NSMutableDictionary *additionalParameters = [@{} mutableCopy]; + if (_configuration.serverClientID) { + additionalParameters[kAudienceParameter] = _configuration.serverClientID; + } + if (_configuration.openIDRealm) { + additionalParameters[kOpenIDRealmParameter] = _configuration.openIDRealm; + } + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + if (_flowName == SignIn) { + NSDictionary *params = + authState.lastAuthorizationResponse.additionalParameters; + NSString *passcodeInfoRequired = (NSString *)params[kEMMPasscodeInfoRequiredKeyName]; + [additionalParameters addEntriesFromDictionary: + [GIDEMMSupport parametersWithParameters:@{} + emmSupport:authFlow.emmSupport + isPasscodeInfoRequired:passcodeInfoRequired.length > 0]]; + } +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); + additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); + + OIDTokenRequest *tokenRequest; + if (!authState.lastTokenResponse.accessToken && + authState.lastAuthorizationResponse.authorizationCode) { + tokenRequest = [authState.lastAuthorizationResponse + tokenExchangeRequestWithAdditionalParameters:additionalParameters]; + } else { + [additionalParameters + addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; + tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; + } + + [authFlow wait]; + [OIDAuthorizationService + performTokenRequest:tokenRequest + callback:^(OIDTokenResponse *_Nullable tokenResponse, + NSError *_Nullable error) { + [authState updateWithTokenResponse:tokenResponse error:error]; + authFlow.error = error; + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + if (authFlow.emmSupport) { + [GIDEMMSupport handleTokenFetchEMMError:error completion:^(NSError *error) { + authFlow.error = error; + [authFlow next]; + }]; + } else { + [authFlow next]; + } +#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST + [authFlow next]; +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + }]; +} + +- (void)authorizationCodeErrorWithAuthFlow:(GIDAuthFlow *)authFlow { + // There was a failure, convert to appropriate error code. + NSDictionary *params = _authorizationResponse.additionalParameters; + NSString *errorString = (NSString *)params[kOAuth2ErrorKeyName]; + + switch (_flowName) { + case SignIn: { + GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + if (authFlow.emmSupport) { + [authFlow wait]; + BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] + handleErrorFromResponse:params + completion:^{ + [authFlow next]; + }]; + if (isEMMError) { + errorCode = kGIDSignInErrorCodeEMM; + } + } +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + if ([errorString isEqualToString:kOAuth2AccessDenied]) { + errorCode = kGIDSignInErrorCodeCanceled; + } + + authFlow.error = [self errorWithString:errorString code:errorCode]; + break; + case Verify: { + GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + if ([errorString isEqualToString:kOAuth2AccessDenied]) { + errorCode = kGIDVerifyErrorCodeCanceled; + } + + authFlow.error = [self errorWithString:errorString code:errorCode]; + break; + } + } + } +} + +- (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow + error:(NSError *)error { + NSString *errorString = [error localizedDescription]; + switch (_flowName) { + case SignIn: { + GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; + if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { + // The user has canceled the flow at the iOS modal dialog. + errorString = kUserCanceledSignInError; + errorCode = kGIDSignInErrorCodeCanceled; + } + authFlow.error = [self errorWithString:errorString code:errorCode]; + break; + } + case Verify: { + GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { + errorString = kUserCanceledVerifyError; + errorCode = kGIDVerifyErrorCodeCanceled; + } + + authFlow.error = [self errorWithString:errorString code:errorCode]; + break; + } + } +} + +- (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)code { + if (errorString == nil) { + errorString = @"Unknown error"; + } + NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; + switch (_flowName) { + case SignIn: + return [NSError errorWithDomain:kGIDSignInErrorDomain + code:code + userInfo:errorDict]; + break; + case Verify: + return [NSError errorWithDomain:kGIDVerifyErrorDomain + code:code + userInfo:errorDict]; + break; + } +} + +@end From 5249ae9e3e02412e7d37047f0e4ccdebed630db2 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 17 May 2024 15:59:52 -0700 Subject: [PATCH 35/55] Reduce code duplication between flows using class `GIDAuthorizationResponseHelper`. --- GoogleSignIn/Sources/GIDSignIn.m | 151 ++---------------- GoogleSignIn/Sources/GIDSignInConstants.h | 4 + GoogleSignIn/Sources/GIDSignInConstants.m | 5 + .../Implementations/GIDVerifyAccountDetail.m | 108 ++----------- .../Implementations/GIDVerifyAuthFlow.h | 41 ----- 5 files changed, 35 insertions(+), 274 deletions(-) delete mode 100644 GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 0452b24f..67c0d61c 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -21,11 +21,12 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignInResult.h" +#import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -#import "GoogleSignIn/Sources/GIDCallbackQueue.h" #import "GoogleSignIn/Sources/GIDScopes.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -97,16 +98,10 @@ // Parameters in the callback URL coming back from browser. static NSString *const kAuthorizationCodeKeyName = @"code"; -static NSString *const kOAuth2ErrorKeyName = @"error"; -static NSString *const kOAuth2AccessDenied = @"access_denied"; -static NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; // Error string for unavailable keychain. static NSString *const kKeychainError = @"keychain error"; -// Error string for user cancelations. -static NSString *const kUserCanceledError = @"The user canceled the sign-in flow."; - // User preference key to detect fresh install of the app. static NSString *const kAppHasRunBeforeKey = @"GID_AppHasRunBefore"; @@ -116,22 +111,6 @@ // The delay before the new sign-in flow can be presented after the existing one is cancelled. static const NSTimeInterval kPresentationDelayAfterCancel = 1.0; -// Minimum time to expiration for a restored access token. -static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; - -// The callback queue used for authentication flow. -@interface GIDAuthFlow : GIDCallbackQueue - -@property(nonatomic, strong, nullable) OIDAuthState *authState; -@property(nonatomic, strong, nullable) NSError *error; -@property(nonatomic, copy, nullable) NSString *emmSupport; -@property(nonatomic, nullable) GIDProfileData *profileData; - -@end - -@implementation GIDAuthFlow -@end - @implementation GIDSignIn { // This value is used when sign-in flows are resumed via the handling of a URL. Its value is // set when a sign-in flow is begun via |signInWithOptions:| when the options passed don't @@ -602,55 +581,19 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe return; } - GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; - authFlow.emmSupport = emmSupport; - - if (authorizationResponse) { - if (authorizationResponse.authorizationCode.length) { - authFlow.authState = [[OIDAuthState alloc] - initWithAuthorizationResponse:authorizationResponse]; - // perform auth code exchange - [self maybeFetchToken:authFlow]; - } else { - // There was a failure, convert to appropriate error code. - NSString *errorString; - GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; - NSDictionary *params = authorizationResponse.additionalParameters; - -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - if (authFlow.emmSupport) { - [authFlow wait]; - BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] - handleErrorFromResponse:params - completion:^{ - [authFlow next]; - }]; - if (isEMMError) { - errorCode = kGIDSignInErrorCodeEMM; - } - } -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - errorString = (NSString *)params[kOAuth2ErrorKeyName]; - if ([errorString isEqualToString:kOAuth2AccessDenied]) { - errorCode = kGIDSignInErrorCodeCanceled; - } + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:emmSupport + flowName:SignIn + configuration: + _currentOptions.configuration]; + GIDAuthFlow *authFlow = [responseHelper processWithError:error]; - authFlow.error = [self errorWithString:errorString code:errorCode]; - } - } else { - NSString *errorString = [error localizedDescription]; - GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; - if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { - // The user has canceled the flow at the iOS modal dialog. - errorString = kUserCanceledError; - errorCode = kGIDSignInErrorCodeCanceled; - } - authFlow.error = [self errorWithString:errorString code:errorCode]; + if (authFlow) { + [self addDecodeIdTokenCallback:authFlow]; + [self addSaveAuthCallback:authFlow]; + [self addCompletionCallback:authFlow]; } - - [self addDecodeIdTokenCallback:authFlow]; - [self addSaveAuthCallback:authFlow]; - [self addCompletionCallback:authFlow]; } // Perform authentication with the provided options. @@ -682,75 +625,15 @@ - (void)authenticateWithOptions:(GIDSignInInternalOptions *)options { // Complete the auth flow using saved auth in keychain. GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; authFlow.authState = authState; - [self maybeFetchToken:authFlow]; + GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] init]; + responseHelper.configuration = _currentOptions.configuration; + + [responseHelper maybeFetchToken:authFlow]; [self addDecodeIdTokenCallback:authFlow]; [self addSaveAuthCallback:authFlow]; [self addCompletionCallback:authFlow]; } -// Fetches the access token if necessary as part of the auth flow. -- (void)maybeFetchToken:(GIDAuthFlow *)authFlow { - OIDAuthState *authState = authFlow.authState; - // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. - if (authFlow.error || - (authState.lastTokenResponse.accessToken && - [authState.lastTokenResponse.accessTokenExpirationDate timeIntervalSinceNow] > - kMinimumRestoredAccessTokenTimeToExpire)) { - return; - } - NSMutableDictionary *additionalParameters = [@{} mutableCopy]; - if (_currentOptions.configuration.serverClientID) { - additionalParameters[kAudienceParameter] = _currentOptions.configuration.serverClientID; - } - if (_currentOptions.configuration.openIDRealm) { - additionalParameters[kOpenIDRealmParameter] = _currentOptions.configuration.openIDRealm; - } -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - NSDictionary *params = - authState.lastAuthorizationResponse.additionalParameters; - NSString *passcodeInfoRequired = (NSString *)params[kEMMPasscodeInfoRequiredKeyName]; - [additionalParameters addEntriesFromDictionary: - [GIDEMMSupport parametersWithParameters:@{} - emmSupport:authFlow.emmSupport - isPasscodeInfoRequired:passcodeInfoRequired.length > 0]]; -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); - additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); - - OIDTokenRequest *tokenRequest; - if (!authState.lastTokenResponse.accessToken && - authState.lastAuthorizationResponse.authorizationCode) { - tokenRequest = [authState.lastAuthorizationResponse - tokenExchangeRequestWithAdditionalParameters:additionalParameters]; - } else { - [additionalParameters - addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; - tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; - } - - [authFlow wait]; - [OIDAuthorizationService - performTokenRequest:tokenRequest - callback:^(OIDTokenResponse *_Nullable tokenResponse, - NSError *_Nullable error) { - [authState updateWithTokenResponse:tokenResponse error:error]; - authFlow.error = error; - -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - if (authFlow.emmSupport) { - [GIDEMMSupport handleTokenFetchEMMError:error completion:^(NSError *error) { - authFlow.error = error; - [authFlow next]; - }]; - } else { - [authFlow next]; - } -#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST - [authFlow next]; -#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST - }]; -} - // Adds a callback to the auth flow to save the auth object to |self| and the keychain as well. - (void)addSaveAuthCallback:(GIDAuthFlow *)authFlow { __weak GIDAuthFlow *weakAuthFlow = authFlow; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h index e04db0fa..3dc9fff4 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.h +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -39,3 +39,7 @@ extern NSString *const kLoginHintParameter; /// The name of the hosted domain parameter for the auth and token exchange endpoints. extern NSString *const kHostedDomainParameter; + +extern NSString *const kOAuth2ErrorKeyName; + +extern NSString *const kOAuth2AccessDenied; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m index bb90d37a..8a2dfad7 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.m +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -27,3 +27,8 @@ NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes"; NSString *const kLoginHintParameter = @"login_hint"; NSString *const kHostedDomainParameter = @"hd"; + +// Parameters in the callback URL coming back from browser. +NSString *const kOAuth2ErrorKeyName = @"error"; +NSString *const kOAuth2AccessDenied = @"access_denied"; +NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index af02d99b..c4ba47fa 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -20,8 +20,8 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" -#import "GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h" - +#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthFlow.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" @@ -33,18 +33,14 @@ @import AppAuth; @import GTMSessionFetcherCore; #else -#import #import #import #import -#import #import #import #import -#import -#import -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import #endif @@ -55,16 +51,6 @@ // The error code for Google Identity. NSErrorDomain const kGIDVerifyErrorDomain = @"com.google.GIDVerify"; -// Error string for user cancelations. -static NSString *const kUserCanceledError = @"The user canceled the verification flow."; - -// Parameters in the callback URL coming back from browser. -static NSString *const kOAuth2ErrorKeyName = @"error"; -static NSString *const kOAuth2AccessDenied = @"access_denied"; - -// Minimum time to expiration for a restored access token. -static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; - @implementation GIDVerifyAccountDetail { /// AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; @@ -210,94 +196,18 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse error:(NSError *)error { - GIDVerifyAuthFlow *authFlow = [[GIDVerifyAuthFlow alloc] init]; - - if (authorizationResponse) { - if (authorizationResponse.authorizationCode.length) { - authFlow.authState = - [[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse]; - // perform auth code exchange - [self maybeFetchToken:authFlow]; - } else { - // There was a failure, convert to appropriate error code. - NSString *errorString; - GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; - NSDictionary *params = authorizationResponse.additionalParameters; - - errorString = (NSString *)params[kOAuth2ErrorKeyName]; - if ([errorString isEqualToString:kOAuth2AccessDenied]) { - errorCode = kGIDVerifyErrorCodeCanceled; - } - - authFlow.error = [self errorWithString:errorString code:errorCode]; - } - } else { - NSString *errorString = [error localizedDescription]; - GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; - if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { - errorString = kUserCanceledError; - errorCode = kGIDVerifyErrorCodeCanceled; - } - authFlow.error = [self errorWithString:errorString code:errorCode]; - } + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:nil + flowName:Verify + configuration:_configuration]; + GIDAuthFlow *authFlow = [responseHelper processWithError:error]; // TODO: Add completion callback method (#413). } -- (void)maybeFetchToken:(GIDVerifyAuthFlow *)authFlow { - OIDAuthState *authState = authFlow.authState; - // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. - if (authFlow.error || - (authState.lastTokenResponse.accessToken && - [authState.lastTokenResponse.accessTokenExpirationDate timeIntervalSinceNow] > - kMinimumRestoredAccessTokenTimeToExpire)) { - return; - } - NSMutableDictionary *additionalParameters = [@{} mutableCopy]; - if (_configuration.serverClientID) { - additionalParameters[kAudienceParameter] = _configuration.serverClientID; - } - if (_configuration.openIDRealm) { - additionalParameters[kOpenIDRealmParameter] = _configuration.openIDRealm; - } - additionalParameters[kSDKVersionLoggingParameter] = GIDVersion(); - additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment(); - - OIDTokenRequest *tokenRequest; - if (!authState.lastTokenResponse.accessToken && - authState.lastAuthorizationResponse.authorizationCode) { - tokenRequest = [authState.lastAuthorizationResponse - tokenExchangeRequestWithAdditionalParameters:additionalParameters]; - } else { - [additionalParameters - addEntriesFromDictionary:authState.lastTokenResponse.request.additionalParameters]; - tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; - } - - [authFlow wait]; - [OIDAuthorizationService - performTokenRequest:tokenRequest - callback:^(OIDTokenResponse *_Nullable tokenResponse, - NSError *_Nullable error) { - [authState updateWithTokenResponse:tokenResponse error:error]; - authFlow.error = error; - - [authFlow next]; - }]; -} - #pragma mark - Helpers -- (NSError *)errorWithString:(NSString *)errorString code:(GIDVerifyErrorCode)code { - if (errorString == nil) { - errorString = @"Unknown error"; - } - NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; - return [NSError errorWithDomain:kGIDVerifyErrorDomain - code:code - userInfo:errorDict]; -} - // Assert that a current user exists. - (void)assertValidCurrentUser { if (!GIDSignIn.sharedInstance.currentUser) { diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h deleted file mode 100644 index 94966339..00000000 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAuthFlow.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "GoogleSignIn/Sources/GIDCallbackQueue.h" -#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" - -@import GTMAppAuth; - -#ifdef SWIFT_PACKAGE -@import AppAuth; -@import GTMSessionFetcherCore; -#else -#import -#endif - -/// The callback queue used for authentication flow. -@interface GIDVerifyAuthFlow : GIDCallbackQueue - -/// A representation of the state of the OAuth session for this instance. -@property(nonatomic, strong, nullable) OIDAuthState *authState; - -/// The error thrown from the OAuth session encountered for this instance. -@property(nonatomic, strong, nullable) NSError *error; - -@end - -@implementation GIDVerifyAuthFlow -@end From 2f6d0fefe382d1ad4c0302e84632fa49daf02070 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 17 May 2024 19:36:28 -0700 Subject: [PATCH 36/55] Add preprocessor directives to GIDAuthorizationResponseHelper. --- .../Sources/GIDAuthorizationResponseHelper.m | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m index 22dfb404..58caa5ca 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -165,31 +165,34 @@ - (void)authorizationCodeErrorWithAuthFlow:(GIDAuthFlow *)authFlow { if (authFlow.emmSupport) { [authFlow wait]; BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] - handleErrorFromResponse:params - completion:^{ - [authFlow next]; - }]; + handleErrorFromResponse:params + completion:^{ + [authFlow next]; + }]; if (isEMMError) { errorCode = kGIDSignInErrorCodeEMM; } } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + if ([errorString isEqualToString:kOAuth2AccessDenied]) { errorCode = kGIDSignInErrorCodeCanceled; } authFlow.error = [self errorWithString:errorString code:errorCode]; + } break; case Verify: { +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; if ([errorString isEqualToString:kOAuth2AccessDenied]) { errorCode = kGIDVerifyErrorCodeCanceled; } authFlow.error = [self errorWithString:errorString code:errorCode]; +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST break; } - } } } @@ -208,6 +211,7 @@ - (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow break; } case Verify: { +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { errorString = kUserCanceledVerifyError; @@ -215,6 +219,7 @@ - (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow } authFlow.error = [self errorWithString:errorString code:errorCode]; +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST break; } } @@ -232,9 +237,11 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co userInfo:errorDict]; break; case Verify: +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST return [NSError errorWithDomain:kGIDVerifyErrorDomain code:code userInfo:errorDict]; +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST break; } } From 061b76b4a38cd8197727206652640a34a9bb9295 Mon Sep 17 00:00:00 2001 From: brianna Date: Sun, 19 May 2024 19:12:27 -0700 Subject: [PATCH 37/55] Return instance in GIDAuthorizationResponseHelper initializer. --- GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h | 2 +- GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m | 4 ++-- GoogleSignIn/Sources/GIDSignIn.m | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h index f0e87dd9..ddfbe083 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h @@ -32,7 +32,7 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { @property(nonatomic, strong, nullable) GIDConfiguration *configuration; - (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authFlow - emmSupport:emmSupport + emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName configuration:(GIDConfiguration *)config; diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m index 58caa5ca..d6aeae09 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -56,7 +56,7 @@ @implementation GIDAuthorizationResponseHelper { - (instancetype) initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse - emmSupport:(NSString *)emmSupport + emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName configuration:(GIDConfiguration *)configuration { self = [super init]; @@ -66,6 +66,7 @@ @implementation GIDAuthorizationResponseHelper { _flowName = flowName; _configuration = configuration; } + return self; } - (GIDAuthFlow *)processWithError:(NSError *)error { @@ -217,7 +218,6 @@ - (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow errorString = kUserCanceledVerifyError; errorCode = kGIDVerifyErrorCodeCanceled; } - authFlow.error = [self errorWithString:errorString code:errorCode]; #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST break; diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 67c0d61c..3b5293fe 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -582,11 +582,11 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe } GIDAuthorizationResponseHelper *responseHelper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse - emmSupport:emmSupport - flowName:SignIn - configuration: - _currentOptions.configuration]; + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:emmSupport + flowName:SignIn + configuration: + _currentOptions.configuration]; GIDAuthFlow *authFlow = [responseHelper processWithError:error]; if (authFlow) { From e3a8b3d9892e6f54b7a28a4ca08cabf799ced829 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 20 May 2024 11:07:41 -0700 Subject: [PATCH 38/55] Add test for `GIDAuthorizationResponseHelper`. --- .../Unit/GIDAuthorizationResponseHelperTest.h | 1 + .../Unit/GIDAuthorizationResponseHelperTest.m | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h create mode 100644 GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h @@ -0,0 +1 @@ + diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m new file mode 100644 index 00000000..336c7290 --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" + +#import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h" + +@interface GIDAuthorizationResponseHelperTest : XCTestCase +@end + +@implementation GIDAuthorizationResponseHelperTest + +- (void)testInitWithAuthorizationResponse { + // Mock generating a GIDConfiguration when initializing GIDGoogleUser. + OIDAuthorizationResponse *authResponse = + [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil + errorString:nil]; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; +#pragma GCC diagnostic pop + + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse + emmSupport:nil + flowName:Verify + configuration:configuration]; + + XCTAssertNotNil(responseHelper); + XCTAssertNotNil(responseHelper.authorizationResponse); + XCTAssertNil(responseHelper.emmSupport); + XCTAssertEqual(responseHelper.flowName, Verify); + XCTAssertNotNil(responseHelper.configuration); +} + +@end From 34df26699c9131dc092556b8ddb349e63cebed07 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 20 May 2024 11:08:55 -0700 Subject: [PATCH 39/55] Add documentation and error handling. --- GoogleSignIn/Sources/GIDAuthFlow.h | 3 ++ .../Sources/GIDAuthorizationResponseHelper.h | 41 ++++++++++++++++--- .../Sources/GIDAuthorizationResponseHelper.m | 36 ++++++++-------- GoogleSignIn/Sources/GIDSignIn.m | 2 - GoogleSignIn/Sources/GIDSignInConstants.h | 5 +++ GoogleSignIn/Sources/GIDSignInConstants.m | 1 - .../Implementations/GIDVerifyAccountDetail.m | 7 ++-- 7 files changed, 67 insertions(+), 28 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthFlow.h b/GoogleSignIn/Sources/GIDAuthFlow.h index 3feb087e..0e07b0e3 100644 --- a/GoogleSignIn/Sources/GIDAuthFlow.h +++ b/GoogleSignIn/Sources/GIDAuthFlow.h @@ -30,7 +30,10 @@ /// The error thrown from the OAuth session encountered for this instance. @property(nonatomic, strong, nullable) NSError *error; +/// The EMM support version. @property(nonatomic, copy, nullable) NSString *emmSupport; + +/// The profile data extracted from the ID token. @property(nonatomic, nullable) GIDProfileData *profileData; diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h index ddfbe083..e2c48912 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h @@ -22,22 +22,53 @@ NS_ASSUME_NONNULL_BEGIN +/// A list of potential current flow names. typedef NS_ENUM(NSInteger, GIDFlowName) { +/// The Sign In flow. SignIn, +/// The Verify flow. Verify, }; +/// A helper class to process the authorization response. @interface GIDAuthorizationResponseHelper : NSObject -@property(nonatomic, strong, nullable) GIDConfiguration *configuration; +/// The authorization response to process. +@property(nonatomic, readonly) OIDAuthorizationResponse *authorizationResponse; -- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authFlow - emmSupport:(nullable NSString *)emmSupport - flowName:(GIDFlowName)flowName - configuration:(GIDConfiguration *)config; +/// The EMM support version. +@property(nonatomic, readwrite, nullable) NSString *emmSupport; +/// The name of the current flow. +@property(nonatomic, readonly)GIDFlowName flowName; + +/// The configuration of the current flow. +@property(nonatomic, readwrite) GIDConfiguration *configuration; + +/// Initializes a new instance of the `GIDAuthorizationResponseHelper` class with the provided fields. +/// +/// @param authorizationResponse The authorization response to be processed. +/// @param emmSupport The EMM support version. +/// @param flowName The name of the current flow. +/// @param configuration The configuration. +/// @return A new initialized instance of the `GIDAuthorizationResponseHelper` class. +- (instancetype) + initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse + emmSupport:(nullable NSString *)emmSupport + flowName:(GIDFlowName)flowName + configuration:(nullable GIDConfiguration *)configuration; + +/// Processes the authorization response and returns an auth flow. +/// +/// @param error The error thrown if there's no authorization response. +/// @return An instance of `GIDAuthFlow`. - (GIDAuthFlow *)processWithError:(NSError *)error; + + +/// Fetches the access token if necessary as part of the auth flow. +/// +/// @param authFlow The auth flow to either fetch tokens or error. - (void)maybeFetchToken:(GIDAuthFlow *)authFlow; @end diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m index d6aeae09..614b0ae1 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -21,44 +21,39 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" - - @import GTMAppAuth; #ifdef SWIFT_PACKAGE @import AppAuth; @import GTMSessionFetcherCore; #else +#import #import #import +#import +#import +#import #endif -// Error string for user cancelations. +/// Error string for user cancelations. static NSString *const kUserCanceledSignInError = @"The user canceled the sign-in flow."; static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; - -static NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; - -// Minimum time to expiration for a restored access token. +/// Minimum time to expiration for a restored access token. static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; -@implementation GIDAuthorizationResponseHelper { - OIDAuthorizationResponse *_authorizationResponse; - NSString *_emmSupport; - GIDFlowName _flowName; -} +@implementation GIDAuthorizationResponseHelper - (instancetype) - initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName - configuration:(GIDConfiguration *)configuration { + configuration:(nullable GIDConfiguration *)configuration { self = [super init]; if (self) { _authorizationResponse = authorizationResponse; @@ -88,7 +83,6 @@ - (GIDAuthFlow *)processWithError:(NSError *)error { return authFlow; } -// Fetches the access token if necessary as part of the auth flow. - (void)maybeFetchToken:(GIDAuthFlow *)authFlow { OIDAuthState *authState = authFlow.authState; // Do nothing if we have an auth flow error or a restored access token that isn't near expiration. @@ -229,6 +223,11 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co if (errorString == nil) { errorString = @"Unknown error"; } + + if (!_flowName) { + errorString = @"No specified flow"; + } + NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; switch (_flowName) { case SignIn: @@ -241,9 +240,14 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co return [NSError errorWithDomain:kGIDVerifyErrorDomain code:code userInfo:errorDict]; + break; #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + default: break; } + return [NSError errorWithDomain:kGIDSignInErrorDomain + code:code + userInfo:errorDict]; } @end diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 3b5293fe..971c7e13 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -53,8 +53,6 @@ #import #import #import -#import -#import #import #import diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h index 3dc9fff4..41e49daf 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.h +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -40,6 +40,11 @@ extern NSString *const kLoginHintParameter; /// The name of the hosted domain parameter for the auth and token exchange endpoints. extern NSString *const kHostedDomainParameter; +/// The name of the error key that occurred during the authorization or token exchange process. extern NSString *const kOAuth2ErrorKeyName; +/// The value of the error key when the user cancels the authorization or token exchange process. extern NSString *const kOAuth2AccessDenied; + +/// The name of the key that indicates whether a passocde is required for EMM. +extern NSString *const kEMMPasscodeInfoRequiredKeyName; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m index 8a2dfad7..162e9dfd 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.m +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -28,7 +28,6 @@ NSString *const kLoginHintParameter = @"login_hint"; NSString *const kHostedDomainParameter = @"hd"; -// Parameters in the callback URL coming back from browser. NSString *const kOAuth2ErrorKeyName = @"error"; NSString *const kOAuth2AccessDenied = @"access_denied"; NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index c4ba47fa..7800530f 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -48,8 +48,8 @@ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST -// The error code for Google Identity. -NSErrorDomain const kGIDVerifyErrorDomain = @"com.google.GIDVerify"; +// TODO: Unify error domain across sign-in and verify flow (#425). +NSErrorDomain const kGIDVerifyErrorDomain = @"com.google.GIDVerifyAccountDetail"; @implementation GIDVerifyAccountDetail { /// AppAuth configuration object. @@ -201,9 +201,8 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe emmSupport:nil flowName:Verify configuration:_configuration]; - GIDAuthFlow *authFlow = [responseHelper processWithError:error]; - // TODO: Add completion callback method (#413). + __unused GIDAuthFlow *authFlow = [responseHelper processWithError:error]; } #pragma mark - Helpers From 5953f4e335a38f022138ca5e065bff1b7d7be252 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 20 May 2024 17:02:00 -0700 Subject: [PATCH 40/55] Add designated initializer to `GIDAuthFlow`. --- GoogleSignIn/Sources/GIDAuthFlow.h | 22 ++++++++- GoogleSignIn/Sources/GIDAuthFlow.m | 22 +++++++++ GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m | 54 +++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m diff --git a/GoogleSignIn/Sources/GIDAuthFlow.h b/GoogleSignIn/Sources/GIDAuthFlow.h index 0e07b0e3..26716c7c 100644 --- a/GoogleSignIn/Sources/GIDAuthFlow.h +++ b/GoogleSignIn/Sources/GIDAuthFlow.h @@ -18,6 +18,8 @@ #import "GoogleSignIn/Sources/GIDCallbackQueue.h" +NS_ASSUME_NONNULL_BEGIN + @class OIDAuthState; @class GIDProfileData; @@ -36,6 +38,24 @@ /// The profile data extracted from the ID token. @property(nonatomic, nullable) GIDProfileData *profileData; - +/// Initialize a `GIDAuthFlow` object by specifying all available properties. +/// +/// @param authState The configuration to be used. +/// @param error The configuration to be used. +/// @param emmSupport The configuration to be used. +/// @param profileData The configuration to be used. +/// @return An initialized `GIDAuthFlow` instance. +- (instancetype)initWithAuthState:(nullable OIDAuthState *)authState + error:(nullable NSError *)error + emmSupport:(nullable NSString *)emmSupport + profileData:(nullable GIDProfileData *)profileData + NS_DESIGNATED_INITIALIZER; + +/// Initialize a `GIDAuthFlow` object by calling the designated initializer with `nil` values. +/// +/// @return An initialized `GIDAuthFlow` instance. +- (instancetype)init; @end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthFlow.m b/GoogleSignIn/Sources/GIDAuthFlow.m index 587ff717..d82ceb64 100644 --- a/GoogleSignIn/Sources/GIDAuthFlow.m +++ b/GoogleSignIn/Sources/GIDAuthFlow.m @@ -16,4 +16,26 @@ #import "GoogleSignIn/Sources/GIDAuthFlow.h" @implementation GIDAuthFlow + +- (instancetype)initWithAuthState:(nullable OIDAuthState *)authState + error:(nullable NSError *)error + emmSupport:(nullable NSString *)emmSupport + profileData:(nullable GIDProfileData *)profileData { + self = [super init]; + if (self) { + _authState = authState; + _error = error; + _emmSupport = emmSupport; + _profileData = profileData; + } + return self; +} + +- (instancetype)init { + return [self initWithAuthState:nil + error:nil + emmSupport:nil + profileData:nil]; +} + @end diff --git a/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m b/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m new file mode 100644 index 00000000..fbae509c --- /dev/null +++ b/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +#import "GoogleSignIn/Sources/GIDAuthFlow.h" + +#import "GoogleSignIn/Tests/Unit/GIDProfileData+Testing.h" +#import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" + +@interface GIDAuthFlowTest : XCTestCase +@end + +@implementation GIDAuthFlowTest + +- (void)testInitWithAuthState { + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDProfileData *profileData = [GIDProfileData testInstance]; + + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState + error:nil + emmSupport:nil + profileData:profileData]; + + XCTAssertNotNil(authFlow); + XCTAssertNotNil(authFlow.authState); + XCTAssertNil(authFlow.error); + XCTAssertNil(authFlow.emmSupport); + XCTAssertNotNil(authFlow.profileData); +} + +- (void)testInit { + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; + + XCTAssertNotNil(authFlow); + XCTAssertNil(authFlow.authState); + XCTAssertNil(authFlow.error); + XCTAssertNil(authFlow.emmSupport); + XCTAssertNil(authFlow.profileData); +} + +@end From 77752d8ba2fbb656a136bb8e148c2e2c5c6b5a21 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 20 May 2024 17:06:57 -0700 Subject: [PATCH 41/55] Update documentation, constant names, and `GIDAuthorizationResponseHelper`'s initializer. --- .../Sources/GIDAuthorizationResponseHelper.h | 12 +++--- .../Sources/GIDAuthorizationResponseHelper.m | 43 +++++++++++-------- GoogleSignIn/Sources/GIDSignIn.m | 8 ++-- .../Implementations/GIDVerifyAccountDetail.m | 4 +- .../GoogleSignIn/GIDVerifyAccountDetail.h | 4 +- .../Unit/GIDAuthorizationResponseHelperTest.h | 1 - .../Unit/GIDAuthorizationResponseHelperTest.m | 5 +-- 7 files changed, 40 insertions(+), 37 deletions(-) delete mode 100644 GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h index e2c48912..28fc7179 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h @@ -25,9 +25,9 @@ NS_ASSUME_NONNULL_BEGIN /// A list of potential current flow names. typedef NS_ENUM(NSInteger, GIDFlowName) { /// The Sign In flow. - SignIn, + GIDFlowNameSignIn = 0, /// The Verify flow. - Verify, + GIDFlowNameVerify = 1, }; /// A helper class to process the authorization response. @@ -40,9 +40,9 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { @property(nonatomic, readwrite, nullable) NSString *emmSupport; /// The name of the current flow. -@property(nonatomic, readonly)GIDFlowName flowName; +@property(nonatomic, readonly) GIDFlowName flowName; -/// The configuration of the current flow. +/// The configuration for the current flow. @property(nonatomic, readwrite) GIDConfiguration *configuration; /// Initializes a new instance of the `GIDAuthorizationResponseHelper` class with the provided fields. @@ -53,7 +53,7 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { /// @param configuration The configuration. /// @return A new initialized instance of the `GIDAuthorizationResponseHelper` class. - (instancetype) - initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse + initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName configuration:(nullable GIDConfiguration *)configuration; @@ -64,8 +64,6 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { /// @return An instance of `GIDAuthFlow`. - (GIDAuthFlow *)processWithError:(NSError *)error; - - /// Fetches the access token if necessary as part of the auth flow. /// /// @param authFlow The auth flow to either fetch tokens or error. diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m index 614b0ae1..79fbaac5 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -40,6 +40,8 @@ #import #endif +NS_ASSUME_NONNULL_BEGIN + /// Error string for user cancelations. static NSString *const kUserCanceledSignInError = @"The user canceled the sign-in flow."; static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; @@ -50,7 +52,7 @@ @implementation GIDAuthorizationResponseHelper - (instancetype) - initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse + initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName configuration:(nullable GIDConfiguration *)configuration { @@ -65,8 +67,10 @@ @implementation GIDAuthorizationResponseHelper } - (GIDAuthFlow *)processWithError:(NSError *)error { - GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; - authFlow.emmSupport = _emmSupport; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:nil + error:nil + emmSupport:_emmSupport + profileData:nil]; if (_authorizationResponse) { if (_authorizationResponse.authorizationCode.length) { @@ -74,10 +78,10 @@ - (GIDAuthFlow *)processWithError:(NSError *)error { [[OIDAuthState alloc] initWithAuthorizationResponse:_authorizationResponse]; [self maybeFetchToken:authFlow]; } else { - [self authorizationCodeErrorWithAuthFlow:authFlow]; + [self authorizationCodeErrorToAuthFlow:authFlow]; } } else { - [self authorizationResponseErrorWithAuthFlow:authFlow + [self authorizationResponseErrorToAuthFlow:authFlow error:error]; } return authFlow; @@ -101,7 +105,7 @@ - (void)maybeFetchToken:(GIDAuthFlow *)authFlow { } #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - if (_flowName == SignIn) { + if (_flowName == GIDFlowNameSignIn) { NSDictionary *params = authState.lastAuthorizationResponse.additionalParameters; NSString *passcodeInfoRequired = (NSString *)params[kEMMPasscodeInfoRequiredKeyName]; @@ -148,13 +152,12 @@ - (void)maybeFetchToken:(GIDAuthFlow *)authFlow { }]; } -- (void)authorizationCodeErrorWithAuthFlow:(GIDAuthFlow *)authFlow { - // There was a failure, convert to appropriate error code. +- (void)authorizationCodeErrorToAuthFlow:(GIDAuthFlow *)authFlow { NSDictionary *params = _authorizationResponse.additionalParameters; NSString *errorString = (NSString *)params[kOAuth2ErrorKeyName]; switch (_flowName) { - case SignIn: { + case GIDFlowNameSignIn: { GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST if (authFlow.emmSupport) { @@ -177,11 +180,11 @@ - (void)authorizationCodeErrorWithAuthFlow:(GIDAuthFlow *)authFlow { authFlow.error = [self errorWithString:errorString code:errorCode]; } break; - case Verify: { + case GIDFlowNameVerify: { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + GIDVerifyErrorCode errorCode = GIDVerifyErrorCodeUnknown; if ([errorString isEqualToString:kOAuth2AccessDenied]) { - errorCode = kGIDVerifyErrorCodeCanceled; + errorCode = GIDVerifyErrorCodeCanceled; } authFlow.error = [self errorWithString:errorString code:errorCode]; @@ -191,11 +194,11 @@ - (void)authorizationCodeErrorWithAuthFlow:(GIDAuthFlow *)authFlow { } } -- (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow +- (void)authorizationResponseErrorToAuthFlow:(GIDAuthFlow *)authFlow error:(NSError *)error { NSString *errorString = [error localizedDescription]; switch (_flowName) { - case SignIn: { + case GIDFlowNameSignIn: { GIDSignInErrorCode errorCode = kGIDSignInErrorCodeUnknown; if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { // The user has canceled the flow at the iOS modal dialog. @@ -205,12 +208,12 @@ - (void)authorizationResponseErrorWithAuthFlow:(GIDAuthFlow *)authFlow authFlow.error = [self errorWithString:errorString code:errorCode]; break; } - case Verify: { + case GIDFlowNameVerify: { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - GIDVerifyErrorCode errorCode = kGIDVerifyErrorCodeUnknown; + GIDVerifyErrorCode errorCode = GIDVerifyErrorCodeUnknown; if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { errorString = kUserCanceledVerifyError; - errorCode = kGIDVerifyErrorCodeCanceled; + errorCode = GIDVerifyErrorCodeCanceled; } authFlow.error = [self errorWithString:errorString code:errorCode]; #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -230,12 +233,12 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; switch (_flowName) { - case SignIn: + case GIDFlowNameSignIn: return [NSError errorWithDomain:kGIDSignInErrorDomain code:code userInfo:errorDict]; break; - case Verify: + case GIDFlowNameVerify: #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST return [NSError errorWithDomain:kGIDVerifyErrorDomain code:code @@ -251,3 +254,5 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co } @end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 971c7e13..8adb6e5a 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -582,7 +582,7 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse emmSupport:emmSupport - flowName:SignIn + flowName:GIDFlowNameSignIn configuration: _currentOptions.configuration]; GIDAuthFlow *authFlow = [responseHelper processWithError:error]; @@ -621,8 +621,10 @@ - (void)authenticateWithOptions:(GIDSignInInternalOptions *)options { } // Complete the auth flow using saved auth in keychain. - GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; - authFlow.authState = authState; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState + error:nil + emmSupport:nil + profileData:nil]; GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] init]; responseHelper.configuration = _currentOptions.configuration; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 7800530f..a0d6c9b6 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -54,7 +54,7 @@ @implementation GIDVerifyAccountDetail { /// AppAuth configuration object. OIDServiceConfiguration *_appAuthConfiguration; - // AppAuth external user-agent session state. + /// AppAuth external user-agent session state. id _currentAuthorizationFlow; } @@ -199,7 +199,7 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse emmSupport:nil - flowName:Verify + flowName:GIDFlowNameVerify configuration:_configuration]; // TODO: Add completion callback method (#413). __unused GIDAuthFlow *authFlow = [responseHelper processWithError:error]; diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h index 1ddd3b1a..669800d7 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h @@ -38,9 +38,9 @@ extern NSErrorDomain const kGIDVerifyErrorDomain; /// A list of potential error codes returned from the Google Sign-In SDK. typedef NS_ERROR_ENUM(kGIDVerifyErrorDomain, GIDVerifyErrorCode) { /// Indicates an unknown error has occurred. - kGIDVerifyErrorCodeUnknown = 1, + GIDVerifyErrorCodeUnknown = 0, /// Indicates the user canceled the verification request. - kGIDVerifyErrorCodeCanceled = 2, + GIDVerifyErrorCodeCanceled = 1, }; /// Represents a completion block that takes a `GIDVerifiedAccountDetailResult` on success or an diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h deleted file mode 100644 index 8b137891..00000000 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 336c7290..bc9bf085 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -27,7 +27,6 @@ @interface GIDAuthorizationResponseHelperTest : XCTestCase @implementation GIDAuthorizationResponseHelperTest - (void)testInitWithAuthorizationResponse { - // Mock generating a GIDConfiguration when initializing GIDGoogleUser. OIDAuthorizationResponse *authResponse = [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil errorString:nil]; @@ -39,13 +38,13 @@ - (void)testInitWithAuthorizationResponse { GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse emmSupport:nil - flowName:Verify + flowName:GIDFlowNameVerify configuration:configuration]; XCTAssertNotNil(responseHelper); XCTAssertNotNil(responseHelper.authorizationResponse); XCTAssertNil(responseHelper.emmSupport); - XCTAssertEqual(responseHelper.flowName, Verify); + XCTAssertEqual(responseHelper.flowName, GIDFlowNameVerify); XCTAssertNotNil(responseHelper.configuration); } From 06ff4d2f32a01d09ac1442a941a7428719fff900 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 21 May 2024 13:26:58 -0700 Subject: [PATCH 42/55] Add issue to clean up callback flow in the future. --- GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m | 1 + 1 file changed, 1 insertion(+) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m index 79fbaac5..8731f9d4 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m @@ -129,6 +129,7 @@ - (void)maybeFetchToken:(GIDAuthFlow *)authFlow { tokenRequest = [authState tokenRefreshRequestWithAdditionalParameters:additionalParameters]; } + // TODO: Clean up callback flow (#427). [authFlow wait]; [OIDAuthorizationService performTokenRequest:tokenRequest From 60f276c7f29ee74b72cdd13bc77b359ed0ab3700 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 24 May 2024 13:42:20 -0700 Subject: [PATCH 43/55] Add GIDAuthorizationResponseHandling and fake for testing. --- .../GIDAuthorizationResponseHandlingFake.h | 47 ++++++ .../GIDAuthorizationResponseHandlingFake.m | 62 ++++++++ .../GIDAuthorizationResponseHandler.h | 26 ++++ .../GIDAuthorizationResponseHandler.m} | 44 ++++-- .../GIDAuthorizationResponseHandling.h} | 42 ++--- .../GIDAuthorizationResponseHelper.h | 53 +++++++ .../GIDAuthorizationResponseHelper.m | 70 +++++++++ GoogleSignIn/Sources/GIDSignIn.m | 41 +++-- GoogleSignIn/Sources/GIDSignInConstants.h | 9 ++ GoogleSignIn/Sources/GIDSignInConstants.m | 5 + .../Implementations/GIDVerifyAccountDetail.m | 18 ++- .../Unit/GIDAuthorizationResponseHelperTest.m | 146 +++++++++++++++++- 12 files changed, 500 insertions(+), 63 deletions(-) create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h rename GoogleSignIn/Sources/{GIDAuthorizationResponseHelper.m => GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m} (88%) rename GoogleSignIn/Sources/{GIDAuthorizationResponseHelper.h => GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h} (69%) create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h create mode 100644 GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h new file mode 100644 index 00000000..17423b95 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" + +NS_ASSUME_NONNULL_BEGIN + +@class OIDAuthState; + +@interface GIDAuthorizationResponseHandlingFake : NSObject + +/// The auth state to be used to fetch tokens. +@property (nonatomic, nullable) OIDAuthState *authState; + +/// The error to be passed into the completion. +@property (nonatomic, nullable) NSError *error; + +/// Creates an instance conforming to `GIDAuthorizationResponseHandling` with the provided +/// auth state and error. +/// +/// @param authState The `OIDAuthState` instance to access tokens. +/// @param error The `NSError` to pass into the completion. +- (instancetype)initWithAuthState:(nullable OIDAuthState *)authState + error:(nullable NSError *)error; + +/// Fill the passed in auth flow with the auth state and error initialized. +/// +/// @param authFlow The auth flow to either fetch tokens or error. +//- (void)maybeFetchToken:(GIDAuthFlow *)authFlow; +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m new file mode 100644 index 00000000..c0d5ec17 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h" + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" + +#import "GoogleSignIn/Sources/GIDAuthFlow.h" + +@implementation GIDAuthorizationResponseHandlingFake + +- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + emmSupport:(NSString *)emmSupport + flowName:(enum GIDFlowName)flowName + configuration:(GIDConfiguration *)configuration + error:(NSError *)error { + self = [super init]; + if (self) { + NSAssert(false, @"This class is only to be used in testing. Do not use."); + } + return self; +} + +- (instancetype)initWithAuthState:(nullable OIDAuthState *)authState + error:(nullable NSError *)error { + self = [super init]; + if (self) { + _authState = authState; + _error = error; + } + return self; +} + +- (void)maybeFetchToken:(GIDAuthFlow *)authFlow { + authFlow.authState = self.authState; + authFlow.error = self.error; +} + +- (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:self.authState + error:self.error + emmSupport:nil + profileData:nil]; + return authFlow; +} + + +@end + diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h new file mode 100644 index 00000000..00f769b7 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GIDAuthorizationResponseHandler : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m similarity index 88% rename from GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m rename to GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m index 8731f9d4..fda55c86 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m @@ -14,16 +14,19 @@ * limitations under the License. */ -#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" + #import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" -#import "GoogleSignIn/Sources/GIDSignInConstants.h" + #import "GoogleSignIn/Sources/GIDSignInPreferences.h" @import GTMAppAuth; @@ -40,33 +43,45 @@ #import #endif -NS_ASSUME_NONNULL_BEGIN +@interface GIDAuthorizationResponseHandler () + +/// The authorization response to process. +@property(nonatomic, nullable) OIDAuthorizationResponse *authorizationResponse; + +/// The EMM support version. +@property(nonatomic, nullable) NSString *emmSupport; -/// Error string for user cancelations. -static NSString *const kUserCanceledSignInError = @"The user canceled the sign-in flow."; -static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; +/// The name of the current flow. +@property(nonatomic) GIDFlowName flowName; -/// Minimum time to expiration for a restored access token. -static const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; +/// The configuration for the current flow. +@property(nonatomic, nullable) GIDConfiguration *configuration; -@implementation GIDAuthorizationResponseHelper +/// The configuration for the current flow. +@property(nonatomic, nullable) NSError *error; + +@end + +@implementation GIDAuthorizationResponseHandler - (instancetype) - initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse emmSupport:(nullable NSString *)emmSupport flowName:(GIDFlowName)flowName - configuration:(nullable GIDConfiguration *)configuration { + configuration:(nullable GIDConfiguration *)configuration + error:(nullable NSError *)error { self = [super init]; if (self) { _authorizationResponse = authorizationResponse; _emmSupport = emmSupport; _flowName = flowName; _configuration = configuration; + _error = error; } return self; } -- (GIDAuthFlow *)processWithError:(NSError *)error { +- (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:nil error:nil emmSupport:_emmSupport @@ -82,7 +97,7 @@ - (GIDAuthFlow *)processWithError:(NSError *)error { } } else { [self authorizationResponseErrorToAuthFlow:authFlow - error:error]; + error:_error]; } return authFlow; } @@ -254,6 +269,5 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co userInfo:errorDict]; } -@end -NS_ASSUME_NONNULL_END +@end diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h similarity index 69% rename from GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h rename to GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h index 28fc7179..b0df1015 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h @@ -16,6 +16,9 @@ #import +// ?? +//#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" + @class GIDAuthFlow; @class GIDConfiguration; @class OIDAuthorizationResponse; @@ -30,45 +33,34 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { GIDFlowNameVerify = 1, }; -/// A helper class to process the authorization response. -@interface GIDAuthorizationResponseHelper : NSObject - -/// The authorization response to process. -@property(nonatomic, readonly) OIDAuthorizationResponse *authorizationResponse; - -/// The EMM support version. -@property(nonatomic, readwrite, nullable) NSString *emmSupport; - -/// The name of the current flow. -@property(nonatomic, readonly) GIDFlowName flowName; +@protocol GIDAuthorizationResponseHandling -/// The configuration for the current flow. -@property(nonatomic, readwrite) GIDConfiguration *configuration; - -/// Initializes a new instance of the `GIDAuthorizationResponseHelper` class with the provided fields. +/// Initializes a new instance of the `GIDAuthorizationResponseHandling` class with the provided fields. /// /// @param authorizationResponse The authorization response to be processed. /// @param emmSupport The EMM support version. /// @param flowName The name of the current flow. /// @param configuration The configuration. -/// @return A new initialized instance of the `GIDAuthorizationResponseHelper` class. +/// @param error The error thrown if there's no authorization response. +/// @return A new initialized instance of the `GIDAuthorizationResponseHandling` class. - (instancetype) - initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse + initWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse emmSupport:(nullable NSString *)emmSupport - flowName:(GIDFlowName)flowName - configuration:(nullable GIDConfiguration *)configuration; - -/// Processes the authorization response and returns an auth flow. -/// -/// @param error The error thrown if there's no authorization response. -/// @return An instance of `GIDAuthFlow`. -- (GIDAuthFlow *)processWithError:(NSError *)error; + flowName:(enum GIDFlowName)flowName + configuration:(nullable GIDConfiguration *)configuration + error:(nullable NSError *)error; /// Fetches the access token if necessary as part of the auth flow. /// /// @param authFlow The auth flow to either fetch tokens or error. - (void)maybeFetchToken:(GIDAuthFlow *)authFlow; +/// Processes the authorization response and returns an auth flow. +/// +/// @return An instance of `GIDAuthFlow`. +- (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse; + + @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h new file mode 100644 index 00000000..dbe16911 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" + +@class GIDAuthFlow; +@class GIDConfiguration; +@class OIDAuthorizationResponse; + +NS_ASSUME_NONNULL_BEGIN + +/// A helper class to process the authorization response. +@interface GIDAuthorizationResponseHelper : NSObject + +/// The response handler used to process the authorization response. +@property (nonatomic, readonly) id responseHandler; + +/// Initializes a new instance of the `GIDAuthorizationResponseHelper` class with the provided field. +/// +/// @param responseHandler +/// @return A new initialized instance of the `GIDAuthorizationResponseHelper` class. +- (instancetype) +initWithAuthorizationResponseHandler:(id)responseHandler; + +/// Fetches the access token if necessary using the response handler as part of the auth flow. +/// +/// @param authFlow The auth flow to either fetch tokens or error. +- (void)fetchTokenWithAuthFlow:(GIDAuthFlow *)authFlow; + + +/// Processes the initialized authorization response and returns a filled `GIDAuthFlow` instance. +/// +/// @return An instance of `GIDAuthFlow` to either fetch tokens or error. +- (GIDAuthFlow *)fetchAuthFlowFromProcessedResponse; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m new file mode 100644 index 00000000..5a9087c2 --- /dev/null +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m @@ -0,0 +1,70 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" + +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" + +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" + +#import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" +#import "GoogleSignIn/Sources/GIDEMMSupport.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" +#import "GoogleSignIn/Sources/GIDSignInPreferences.h" + +@import GTMAppAuth; + +#ifdef SWIFT_PACKAGE +@import AppAuth; +@import GTMSessionFetcherCore; +#else +#import +#import +#import +#import +#import +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +@implementation GIDAuthorizationResponseHelper + +- (instancetype) +initWithAuthorizationResponseHandler:(id)responseHandler { + self = [super init]; + if (self) { + _responseHandler = responseHandler; + } + return self; +} + +- (void)fetchTokenWithAuthFlow:(GIDAuthFlow *)authFlow { + [self.responseHandler maybeFetchToken:authFlow]; +} + +- (GIDAuthFlow *)fetchAuthFlowFromProcessedResponse { + GIDAuthFlow *authFlow = [self.responseHandler generateAuthFlowFromAuthorizationResponse]; + [self fetchTokenWithAuthFlow:authFlow]; + + return authFlow; +} +@end + +NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index 8adb6e5a..c0955ffc 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -21,8 +21,10 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignInResult.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" + #import "GoogleSignIn/Sources/GIDAuthFlow.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" @@ -570,8 +572,8 @@ - (void)authenticateInteractivelyWithOptions:(GIDSignInInternalOptions *)options }]; } -- (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse - error:(NSError *)error +- (void)processAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse + error:(nullable NSError *)error emmSupport:(NSString *)emmSupport{ if (_restarting) { // The auth flow is restarting, so the work here would be performed in the next round. @@ -579,13 +581,17 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe return; } - GIDAuthorizationResponseHelper *responseHelper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse - emmSupport:emmSupport - flowName:GIDFlowNameSignIn - configuration: - _currentOptions.configuration]; - GIDAuthFlow *authFlow = [responseHelper processWithError:error]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:emmSupport + flowName:GIDFlowNameSignIn + configuration: + _currentOptions.configuration + error:error]; + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; + + GIDAuthFlow *authFlow = [responseHelper fetchAuthFlowFromProcessedResponse]; if (authFlow) { [self addDecodeIdTokenCallback:authFlow]; @@ -625,10 +631,17 @@ - (void)authenticateWithOptions:(GIDSignInInternalOptions *)options { error:nil emmSupport:nil profileData:nil]; - GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] init]; - responseHelper.configuration = _currentOptions.configuration; - - [responseHelper maybeFetchToken:authFlow]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil + emmSupport:nil + flowName:GIDFlowNameSignIn + configuration: + _currentOptions.configuration + error:nil]; + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; + + [responseHelper fetchTokenWithAuthFlow:authFlow]; [self addDecodeIdTokenCallback:authFlow]; [self addSaveAuthCallback:authFlow]; [self addCompletionCallback:authFlow]; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.h b/GoogleSignIn/Sources/GIDSignInConstants.h index 41e49daf..aa06346e 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.h +++ b/GoogleSignIn/Sources/GIDSignInConstants.h @@ -48,3 +48,12 @@ extern NSString *const kOAuth2AccessDenied; /// The name of the key that indicates whether a passocde is required for EMM. extern NSString *const kEMMPasscodeInfoRequiredKeyName; + +/// The error string for user cancelation in the sign-in flow. +extern NSString *const kUserCanceledSignInError; + +/// The error string for user cancelation in the verify flow. +extern NSString *const kUserCanceledVerifyError; + +/// Minimum time to expiration for a restored access token. +extern const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire; diff --git a/GoogleSignIn/Sources/GIDSignInConstants.m b/GoogleSignIn/Sources/GIDSignInConstants.m index 162e9dfd..93e30994 100644 --- a/GoogleSignIn/Sources/GIDSignInConstants.m +++ b/GoogleSignIn/Sources/GIDSignInConstants.m @@ -31,3 +31,8 @@ NSString *const kOAuth2ErrorKeyName = @"error"; NSString *const kOAuth2AccessDenied = @"access_denied"; NSString *const kEMMPasscodeInfoRequiredKeyName = @"emm_passcode_info_required"; + +NSString *const kUserCanceledSignInError = @"The user canceled the sign-in flow."; +NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; + +const NSTimeInterval kMinimumRestoredAccessTokenTimeToExpire = 600.0; diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index a0d6c9b6..79a64bc1 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -20,7 +20,9 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" + #import "GoogleSignIn/Sources/GIDAuthFlow.h" #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h" #import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h" @@ -196,13 +198,17 @@ - (void)verifyAccountDetailsInteractivelyWithOptions:(GIDSignInInternalOptions * - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse error:(NSError *)error { + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:_configuration + error:error]; GIDAuthorizationResponseHelper *responseHelper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authorizationResponse - emmSupport:nil - flowName:GIDFlowNameVerify - configuration:_configuration]; + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; + // TODO: Add completion callback method (#413). - __unused GIDAuthFlow *authFlow = [responseHelper processWithError:error]; + __unused GIDAuthFlow *authFlow = [responseHelper fetchAuthFlowFromProcessedResponse]; } #pragma mark - Helpers diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index bc9bf085..b788503e 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -15,10 +15,14 @@ */ #import -#import "GoogleSignIn/Sources/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/GIDAuthFlow.h" + #import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h" @interface GIDAuthorizationResponseHelperTest : XCTestCase @@ -26,7 +30,27 @@ @interface GIDAuthorizationResponseHelperTest : XCTestCase @implementation GIDAuthorizationResponseHelperTest -- (void)testInitWithAuthorizationResponse { +/*- (void)testInitWithAuthorizationResponseHandler { + OIDAuthorizationResponse *authResponse = + [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil + errorString:nil]; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; +#pragma GCC diagnostic pop + + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authResponse + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:configuration + error:nil]; + + GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHelper]; +}*/ + +/*- (void)testInitWithAuthorizationResponse { OIDAuthorizationResponse *authResponse = [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil errorString:nil]; @@ -35,7 +59,7 @@ - (void)testInitWithAuthorizationResponse { GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; #pragma GCC diagnostic pop - GIDAuthorizationResponseHelper *responseHelper = + GIDAuthorizationResponseHelper *responseHandler = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse emmSupport:nil flowName:GIDFlowNameVerify @@ -46,6 +70,122 @@ - (void)testInitWithAuthorizationResponse { XCTAssertNil(responseHelper.emmSupport); XCTAssertEqual(responseHelper.flowName, GIDFlowNameVerify); XCTAssertNotNil(responseHelper.configuration); +}*/ + +///processWithError +/// 1. successful authorization code flow +/// 2. authorization code error +/// 3. authorization response error flow +/// 4. emmHandling +/* +- (void)testSuccessfulProcessWithError { + OIDAuthorizationResponse *authResponse = + [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil + errorString:nil]; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; +#pragma GCC diagnostic pop + + GIDAuthorizationResponseHandlingFake *responseHandler = + [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthorizationResponse:authResponse + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:configuration]; + + GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; + +// GIDAuthorizationResponseHelper *responseHelper = +// [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse +// emmSupport:nil +// flowName:GIDFlowNameVerify +// configuration:configuration]; + // Create mock for presenting the authorization request. + GIDAuthFlow *authFlow = [responseHelper processWithError:error]; + // maybe fetch token checks + + XCTAssertNotNil(authFlow); + XCTAssertNotNil(authFlow.authState); +} + +- (void)testProcessWithError_noAuthorizationResponse { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDAuthorizationResponseHelper *helper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:nil]; +#pragma GCC diagnostic pop + + static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; + NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain + code:GIDVerifyErrorCodeCanceled + userInfo:nil]; + NSError *_Nullable error; + GIDAuthFlow *authFlow = [helper processWithError:error]; + + XCTAssertNil(authFlow.authState); + XCTAssertNotNil(authFlow.error); + XCTAssertEqual(authFlow.error, error); + XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); +} + +- (void)testProcessWithError_noAuthorizationCode { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDAuthorizationResponseHelper *helper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:nil]; +#pragma GCC diagnostic pop + + static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; + NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain + code:GIDVerifyErrorCodeCanceled + userInfo:nil]; + NSError *_Nullable error; + GIDAuthFlow *authFlow = [helper processWithError:error]; + + XCTAssertNil(authFlow.authState); + XCTAssertNotNil(authFlow.error); + XCTAssertEqual(authFlow.error, error); + XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); +} + +// Repeat for `GIDFlowNameSignIn` + +- (void)testProcessWithError_noAuthorizationCodeWithEMMSupport { + // The EMM support version + static NSString *const kEMMVersion = @"1"; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + GIDAuthorizationResponseHelper *helper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil + emmSupport:kEMMVersion + flowName:GIDFlowNameSignIn + configuration:nil]; +#pragma GCC diagnostic pop + + static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; + NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain + code:GIDVerifyErrorCodeCanceled + userInfo:nil]; + NSError *_Nullable error; + GIDAuthFlow *authFlow = [helper processWithError:error]; + + XCTAssertNil(authFlow.authState); + XCTAssertNotNil(authFlow.emmSupport); + XCTAssertNotNil(authFlow.error); + XCTAssertEqual(authFlow.error, error); + XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); } +/// maybeFetchToken +/// 1. Return if there's an auth flow error or restored access token that isn't near expiration +/// 2. Handle EMMSupport for GIDSignIn flow +/// 3. token request with additional parameters +/// +*/ @end From 5999eb0ed5e2d9f7eeabc093dc6bd72d80a5923f Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 24 May 2024 15:47:41 -0700 Subject: [PATCH 44/55] Remove extra fetch token call to fix tests. --- .../Implementations/GIDAuthorizationResponseHelper.m | 1 - 1 file changed, 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m index 5a9087c2..2ea1d6d2 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m @@ -61,7 +61,6 @@ - (void)fetchTokenWithAuthFlow:(GIDAuthFlow *)authFlow { - (GIDAuthFlow *)fetchAuthFlowFromProcessedResponse { GIDAuthFlow *authFlow = [self.responseHandler generateAuthFlowFromAuthorizationResponse]; - [self fetchTokenWithAuthFlow:authFlow]; return authFlow; } From fab6b4116e9d293904845add4e39cc7abe0dd289 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 24 May 2024 16:02:46 -0700 Subject: [PATCH 45/55] Add doc comment to `responseHandler` param. --- .../Implementations/GIDAuthorizationResponseHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h index dbe16911..30dc29bf 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN /// Initializes a new instance of the `GIDAuthorizationResponseHelper` class with the provided field. /// -/// @param responseHandler +/// @param responseHandler The response handler with the authorization response to process. /// @return A new initialized instance of the `GIDAuthorizationResponseHelper` class. - (instancetype) initWithAuthorizationResponseHandler:(id)responseHandler; From 7dc4c283ee954703d1b99db67d2733787aee110d Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 29 May 2024 11:20:30 -0700 Subject: [PATCH 46/55] Move GIDAuthorizationResponse related files to designated directories. --- .../GIDAuthorizationResponseHandling.h | 4 ---- .../Fake/GIDAuthorizationResponseHandlingFake.h | 6 +----- .../Fake/GIDAuthorizationResponseHandlingFake.m | 11 +++++------ .../GIDAuthorizationResponseHelper.h | 2 +- .../GIDAuthorizationResponseHelper.m | 4 ++-- .../Implementations/GIDAuthorizationResponseHandler.h | 2 +- .../Implementations/GIDAuthorizationResponseHandler.m | 2 +- GoogleSignIn/Sources/GIDSignIn.m | 2 +- .../Implementations/GIDVerifyAccountDetail.m | 2 +- 9 files changed, 13 insertions(+), 22 deletions(-) rename GoogleSignIn/Sources/GIDAuthorizationResponse/{Implementations => API}/GIDAuthorizationResponseHandling.h (95%) rename GoogleSignIn/Sources/GIDAuthorizationResponse/{Implementations => }/GIDAuthorizationResponseHelper.h (94%) rename GoogleSignIn/Sources/GIDAuthorizationResponse/{Implementations => }/GIDAuthorizationResponseHelper.m (90%) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h similarity index 95% rename from GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h rename to GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h index b0df1015..0d88e68b 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h @@ -16,9 +16,6 @@ #import -// ?? -//#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" - @class GIDAuthFlow; @class GIDConfiguration; @class OIDAuthorizationResponse; @@ -60,7 +57,6 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { /// @return An instance of `GIDAuthFlow`. - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse; - @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h index 17423b95..e1fb7c67 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h @@ -16,7 +16,7 @@ #import -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" NS_ASSUME_NONNULL_BEGIN @@ -38,10 +38,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithAuthState:(nullable OIDAuthState *)authState error:(nullable NSError *)error; -/// Fill the passed in auth flow with the auth state and error initialized. -/// -/// @param authFlow The auth flow to either fetch tokens or error. -//- (void)maybeFetchToken:(GIDAuthFlow *)authFlow; @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m index c0d5ec17..1cba5ebe 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m @@ -16,7 +16,7 @@ #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" @@ -44,11 +44,6 @@ - (instancetype)initWithAuthState:(nullable OIDAuthState *)authState return self; } -- (void)maybeFetchToken:(GIDAuthFlow *)authFlow { - authFlow.authState = self.authState; - authFlow.error = self.error; -} - - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:self.authState error:self.error @@ -57,6 +52,10 @@ - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { return authFlow; } +- (void)maybeFetchToken:(GIDAuthFlow *)authFlow { + authFlow.authState = self.authState; + authFlow.error = self.error; +} @end diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h similarity index 94% rename from GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h rename to GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h index 30dc29bf..8f80054d 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h @@ -16,7 +16,7 @@ #import -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" @class GIDAuthFlow; @class GIDConfiguration; diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m similarity index 90% rename from GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m rename to GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m index 2ea1d6d2..63b78f99 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m @@ -14,9 +14,9 @@ * limitations under the License. */ -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h index 00f769b7..8eb3d8a3 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h @@ -16,7 +16,7 @@ #import -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandling.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m index fda55c86..940fc2bc 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m @@ -20,7 +20,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" #import "GoogleSignIn/Sources/GIDSignInConstants.h" diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index c0955ffc..bae9e36e 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -21,7 +21,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignInResult.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 79a64bc1..93cba93b 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -20,7 +20,7 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiableAccountDetail.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifiedAccountDetailResult.h" -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" From 6228850692de147564209f2cefa0c0893b4f7edc Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 29 May 2024 11:20:51 -0700 Subject: [PATCH 47/55] Add testing for class GIDAuthorizationResponseHelper. --- .../Unit/GIDAuthorizationResponseHelperTest.m | 227 ++++++++---------- .../Unit/OIDAuthorizationResponse+Testing.h | 4 + .../Unit/OIDAuthorizationResponse+Testing.m | 18 ++ 3 files changed, 122 insertions(+), 127 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index b788503e..b3541ed8 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -15,7 +15,7 @@ */ #import -#import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHelper.h" +#import "GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.h" #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h" #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" @@ -24,168 +24,141 @@ #import "GoogleSignIn/Sources/GIDAuthFlow.h" #import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h" +#import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" + +// The EMM support version +static NSString *const kEMMVersion = @"1"; @interface GIDAuthorizationResponseHelperTest : XCTestCase @end @implementation GIDAuthorizationResponseHelperTest -/*- (void)testInitWithAuthorizationResponseHandler { - OIDAuthorizationResponse *authResponse = - [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil - errorString:nil]; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; -#pragma GCC diagnostic pop - +- (void)testInitWithAuthorizationResponseHandler { GIDAuthorizationResponseHandler *responseHandler = - [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authResponse + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil emmSupport:nil flowName:GIDFlowNameVerify - configuration:configuration + configuration:nil error:nil]; + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; - GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHelper]; -}*/ + XCTAssertNotNil(responseHelper); + XCTAssertNotNil(responseHelper.responseHandler); +} -/*- (void)testInitWithAuthorizationResponse { - OIDAuthorizationResponse *authResponse = - [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil - errorString:nil]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; -#pragma GCC diagnostic pop +- (void)testFetchTokenWithAuthFlow { + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDAuthorizationResponseHandlingFake *fakeHandler = + [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; + GIDAuthorizationResponseHelper *responseHelper = + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:fakeHandler]; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; - GIDAuthorizationResponseHelper *responseHandler = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse - emmSupport:nil - flowName:GIDFlowNameVerify - configuration:configuration]; + [responseHelper fetchTokenWithAuthFlow:authFlow]; + XCTAssertNotNil(authFlow); + XCTAssertNotNil(authFlow.authState); + XCTAssertNil(authFlow.error); +} - XCTAssertNotNil(responseHelper); - XCTAssertNotNil(responseHelper.authorizationResponse); - XCTAssertNil(responseHelper.emmSupport); - XCTAssertEqual(responseHelper.flowName, GIDFlowNameVerify); - XCTAssertNotNil(responseHelper.configuration); -}*/ - -///processWithError -/// 1. successful authorization code flow -/// 2. authorization code error -/// 3. authorization response error flow -/// 4. emmHandling -/* -- (void)testSuccessfulProcessWithError { - OIDAuthorizationResponse *authResponse = - [OIDAuthorizationResponse testInstanceWithAdditionalParameters:nil - errorString:nil]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDConfiguration *configuration = [[GIDConfiguration alloc] initWithClientID:nil]; -#pragma GCC diagnostic pop - - GIDAuthorizationResponseHandlingFake *responseHandler = - [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthorizationResponse:authResponse +- (void)testSuccessfulGenerateAuthFlowFromAuthorizationResponse { + OIDAuthorizationResponse *authorizationResponse = [OIDAuthorizationResponse testInstance]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse emmSupport:nil - flowName:GIDFlowNameVerify - configuration:configuration]; - - GIDAuthorizationResponseHelper *responseHelper = [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; - -// GIDAuthorizationResponseHelper *responseHelper = -// [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:authResponse -// emmSupport:nil -// flowName:GIDFlowNameVerify -// configuration:configuration]; - // Create mock for presenting the authorization request. - GIDAuthFlow *authFlow = [responseHelper processWithError:error]; - // maybe fetch token checks + flowName:GIDFlowNameVerify + configuration:nil + error:nil]; + GIDAuthFlow *authFlow = [responseHandler generateAuthFlowFromAuthorizationResponse]; XCTAssertNotNil(authFlow); XCTAssertNotNil(authFlow.authState); + XCTAssertNil(authFlow.error); } -- (void)testProcessWithError_noAuthorizationResponse { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDAuthorizationResponseHelper *helper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil - emmSupport:nil - flowName:GIDFlowNameVerify - configuration:nil]; -#pragma GCC diagnostic pop - - static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; +- (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { + NSDictionary *errorDict = + @{ NSLocalizedDescriptionKey : @"Unknown error" }; NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain - code:GIDVerifyErrorCodeCanceled - userInfo:nil]; - NSError *_Nullable error; - GIDAuthFlow *authFlow = [helper processWithError:error]; + code:GIDVerifyErrorCodeUnknown + userInfo:errorDict]; + OIDAuthorizationResponse *authorizationResponse = + [OIDAuthorizationResponse testInstanceNoAuthCodeWithAdditionalParameters:nil + errorString:nil]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:nil + error:nil]; + + GIDAuthFlow *authFlow = [responseHandler generateAuthFlowFromAuthorizationResponse]; + XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error, error); - XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); + XCTAssertEqual(authFlow.error.code, expectedError.code); + XCTAssertEqual(authFlow.error.userInfo[NSLocalizedDescriptionKey], + expectedError.userInfo[NSLocalizedDescriptionKey]); } -- (void)testProcessWithError_noAuthorizationCode { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDAuthorizationResponseHelper *helper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil - emmSupport:nil - flowName:GIDFlowNameVerify - configuration:nil]; -#pragma GCC diagnostic pop - - static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; - NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain - code:GIDVerifyErrorCodeCanceled +- (void)testGenerateAuthFlowWithMissingAuthorizationResponse { + NSError *error = [NSError errorWithDomain:kGIDVerifyErrorDomain + code:GIDVerifyErrorCodeUnknown userInfo:nil]; - NSError *_Nullable error; - GIDAuthFlow *authFlow = [helper processWithError:error]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil + emmSupport:nil + flowName:GIDFlowNameVerify + configuration:nil + error:error]; + GIDAuthFlow *authFlow = [responseHandler generateAuthFlowFromAuthorizationResponse]; + XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error, error); - XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); + XCTAssertEqual(authFlow.error.code, error.code); } -// Repeat for `GIDFlowNameSignIn` - -- (void)testProcessWithError_noAuthorizationCodeWithEMMSupport { - // The EMM support version - static NSString *const kEMMVersion = @"1"; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" - GIDAuthorizationResponseHelper *helper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponse:nil - emmSupport:kEMMVersion - flowName:GIDFlowNameSignIn - configuration:nil]; -#pragma GCC diagnostic pop - - static NSString *const kUserCanceledVerifyError = @"The user canceled the verification flow."; - NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain - code:GIDVerifyErrorCodeCanceled +- (void)testMaybeFetchTokenWithAuthFlowError { + NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain + code:kGIDSignInErrorCodeUnknown userInfo:nil]; - NSError *_Nullable error; - GIDAuthFlow *authFlow = [helper processWithError:error]; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:nil + error:error + emmSupport:nil + profileData:nil]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil + emmSupport:kEMMVersion + flowName:GIDFlowNameSignIn + configuration:nil + error:nil]; + [responseHandler maybeFetchToken:authFlow]; XCTAssertNil(authFlow.authState); - XCTAssertNotNil(authFlow.emmSupport); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error, error); - XCTAssertEqual(authFlow.error.code, GIDVerifyErrorCodeUnknown); + XCTAssertNil(authFlow.emmSupport); +} + +- (void)testMaybeFetchTokenWithExpirationError { + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState + error:nil + emmSupport:nil + profileData:nil]; + GIDAuthorizationResponseHandler *responseHandler = + [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil + emmSupport:kEMMVersion + flowName:GIDFlowNameSignIn + configuration:nil + error:nil]; + + [responseHandler maybeFetchToken:authFlow]; + XCTAssertNotNil(authFlow.authState); + XCTAssertNil(authFlow.error); + XCTAssertNil(authFlow.emmSupport); } -/// maybeFetchToken -/// 1. Return if there's an auth flow error or restored access token that isn't near expiration -/// 2. Handle EMMSupport for GIDSignIn flow -/// 3. token request with additional parameters -/// -*/ @end diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h index 4e15ed45..e0f69141 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h @@ -28,4 +28,8 @@ (NSDictionary *)additionalParameters errorString:(NSString *)errorString; ++ (instancetype)testInstanceNoAuthCodeWithAdditionalParameters: + (NSDictionary *)additionalParameters + errorString:(NSString *)errorString; + @end diff --git a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m index 78608b66..fbc8560c 100644 --- a/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.m @@ -49,4 +49,22 @@ + (instancetype)testInstanceWithAdditionalParameters: parameters:parameters]; } ++ (instancetype)testInstanceNoAuthCodeWithAdditionalParameters: + (NSDictionary *)additionalParameters + errorString:(NSString *)errorString { + NSMutableDictionary *parameters; + if (errorString) { + parameters = [NSMutableDictionary dictionaryWithDictionary:@{ @"error" : errorString }]; + } else { + parameters = [NSMutableDictionary dictionaryWithDictionary:@{ + @"code" : @"", + }]; + if (additionalParameters) { + [parameters addEntriesFromDictionary:additionalParameters]; + } + } + return [[OIDAuthorizationResponse alloc] initWithRequest:[OIDAuthorizationRequest testInstance] + parameters:parameters]; +} + @end From 23c3d17f576d5739457e924321292134eeeaec94 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 29 May 2024 12:03:09 -0700 Subject: [PATCH 48/55] Add imports and preprocessor directives to testing. --- .../Tests/Unit/GIDAuthorizationResponseHelperTest.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index b3541ed8..138b27fb 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -20,7 +20,8 @@ #import "GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" - +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDVerifyAccountDetail.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" #import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h" @@ -78,6 +79,7 @@ - (void)testSuccessfulGenerateAuthFlowFromAuthorizationResponse { } - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : @"Unknown error" }; NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain @@ -101,9 +103,11 @@ - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { XCTAssertEqual(authFlow.error.code, expectedError.code); XCTAssertEqual(authFlow.error.userInfo[NSLocalizedDescriptionKey], expectedError.userInfo[NSLocalizedDescriptionKey]); +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST } - (void)testGenerateAuthFlowWithMissingAuthorizationResponse { +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST NSError *error = [NSError errorWithDomain:kGIDVerifyErrorDomain code:GIDVerifyErrorCodeUnknown userInfo:nil]; @@ -119,6 +123,7 @@ - (void)testGenerateAuthFlowWithMissingAuthorizationResponse { XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); XCTAssertEqual(authFlow.error.code, error.code); +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST } - (void)testMaybeFetchTokenWithAuthFlowError { From 0d567940f9624a97a7f52eb9587e2977dc4d650f Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 29 May 2024 13:53:11 -0700 Subject: [PATCH 49/55] Fix test with no authorization code. --- GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 138b27fb..1d99c228 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -101,8 +101,8 @@ - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); XCTAssertEqual(authFlow.error.code, expectedError.code); - XCTAssertEqual(authFlow.error.userInfo[NSLocalizedDescriptionKey], - expectedError.userInfo[NSLocalizedDescriptionKey]); + XCTAssertEqualObjects(authFlow.error.userInfo[NSLocalizedDescriptionKey], + expectedError.userInfo[NSLocalizedDescriptionKey]); #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST } From d7542926bee4a6dd450c167cfedad64e913f37d3 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 3 Jun 2024 17:16:24 -0700 Subject: [PATCH 50/55] Add doc comments and remove unused imports. --- .../GIDAuthorizationResponseHandlingFake.h | 1 + .../GIDAuthorizationResponseHandlingFake.m | 14 ++++++++++++ .../GIDAuthorizationResponseHelper.m | 3 --- .../GIDAuthorizationResponseHandler.h | 1 + .../GIDAuthorizationResponseHandler.m | 22 ++++++++----------- .../Implementations/GIDVerifyAccountDetail.m | 5 +---- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h index e1fb7c67..3165870e 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.h @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN @class OIDAuthState; +/// A fake implementation of `GIDAuthorizationResponseHandling` for testing purposes. @interface GIDAuthorizationResponseHandlingFake : NSObject /// The auth state to be used to fetch tokens. diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m index 1cba5ebe..f8af5216 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m @@ -19,6 +19,13 @@ #import "GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h" #import "GoogleSignIn/Sources/GIDAuthFlow.h" +#import "GoogleSignIn/Sources/GIDSignInConstants.h" + +#ifdef SWIFT_PACKAGE +@import AppAuth; +#else +#import +#endif @implementation GIDAuthorizationResponseHandlingFake @@ -53,6 +60,13 @@ - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { } - (void)maybeFetchToken:(GIDAuthFlow *)authFlow { + if (authFlow.error || + (_authState.lastTokenResponse.accessToken && + [_authState.lastTokenResponse.accessTokenExpirationDate timeIntervalSinceNow] > + kMinimumRestoredAccessTokenTimeToExpire)) { + return; + } + authFlow.authState = self.authState; authFlow.error = self.error; } diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m index 63b78f99..2ac14de4 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/GIDAuthorizationResponseHelper.m @@ -28,11 +28,8 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -@import GTMAppAuth; - #ifdef SWIFT_PACKAGE @import AppAuth; -@import GTMSessionFetcherCore; #else #import #import diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h index 8eb3d8a3..de2b79a6 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN +/// A class that handles the authorization response and fetch tokens. @interface GIDAuthorizationResponseHandler : NSObject @end diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m index 940fc2bc..11122023 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m @@ -26,14 +26,10 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" - #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -@import GTMAppAuth; - #ifdef SWIFT_PACKAGE @import AppAuth; -@import GTMSessionFetcherCore; #else #import #import @@ -97,7 +93,7 @@ - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { } } else { [self authorizationResponseErrorToAuthFlow:authFlow - error:_error]; + error:_error]; } return authFlow; } @@ -179,10 +175,10 @@ - (void)authorizationCodeErrorToAuthFlow:(GIDAuthFlow *)authFlow { if (authFlow.emmSupport) { [authFlow wait]; BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] - handleErrorFromResponse:params - completion:^{ - [authFlow next]; - }]; + handleErrorFromResponse:params + completion:^{ + [authFlow next]; + }]; if (isEMMError) { errorCode = kGIDSignInErrorCodeEMM; } @@ -196,7 +192,7 @@ - (void)authorizationCodeErrorToAuthFlow:(GIDAuthFlow *)authFlow { authFlow.error = [self errorWithString:errorString code:errorCode]; } break; - case GIDFlowNameVerify: { + case GIDFlowNameVerifyAccountDetail: { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST GIDVerifyErrorCode errorCode = GIDVerifyErrorCodeUnknown; if ([errorString isEqualToString:kOAuth2AccessDenied]) { @@ -211,7 +207,7 @@ - (void)authorizationCodeErrorToAuthFlow:(GIDAuthFlow *)authFlow { } - (void)authorizationResponseErrorToAuthFlow:(GIDAuthFlow *)authFlow - error:(NSError *)error { + error:(NSError *)error { NSString *errorString = [error localizedDescription]; switch (_flowName) { case GIDFlowNameSignIn: { @@ -224,7 +220,7 @@ - (void)authorizationResponseErrorToAuthFlow:(GIDAuthFlow *)authFlow authFlow.error = [self errorWithString:errorString code:errorCode]; break; } - case GIDFlowNameVerify: { + case GIDFlowNameVerifyAccountDetail: { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST GIDVerifyErrorCode errorCode = GIDVerifyErrorCodeUnknown; if (error.code == OIDErrorCodeUserCanceledAuthorizationFlow) { @@ -254,7 +250,7 @@ - (NSError *)errorWithString:(nullable NSString *)errorString code:(NSInteger)co code:code userInfo:errorDict]; break; - case GIDFlowNameVerify: + case GIDFlowNameVerifyAccountDetail: #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST return [NSError errorWithDomain:kGIDVerifyErrorDomain code:code diff --git a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m index 93cba93b..3dfb27e7 100644 --- a/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m +++ b/GoogleSignIn/Sources/GIDVerifyAccountDetail/Implementations/GIDVerifyAccountDetail.m @@ -29,11 +29,8 @@ #import "GoogleSignIn/Sources/GIDSignInConstants.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" -@import GTMAppAuth; - #ifdef SWIFT_PACKAGE @import AppAuth; -@import GTMSessionFetcherCore; #else #import #import @@ -201,7 +198,7 @@ - (void)processAuthorizationResponse:(OIDAuthorizationResponse *)authorizationRe GIDAuthorizationResponseHandler *responseHandler = [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse emmSupport:nil - flowName:GIDFlowNameVerify + flowName:GIDFlowNameVerifyAccountDetail configuration:_configuration error:error]; GIDAuthorizationResponseHelper *responseHelper = From 6ca223cbe2acd8dd88abe5a9ef76bd98ff1d2157 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 3 Jun 2024 17:17:07 -0700 Subject: [PATCH 51/55] Updating testing to check for equality. --- .../API/GIDAuthorizationResponseHandling.h | 2 +- GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m | 4 +- .../Unit/GIDAuthorizationResponseHelperTest.m | 102 +++++++++++------- .../Tests/Unit/OIDTokenResponse+Testing.h | 2 + .../Tests/Unit/OIDTokenResponse+Testing.m | 8 ++ 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h index 0d88e68b..2f2bfe22 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h @@ -27,7 +27,7 @@ typedef NS_ENUM(NSInteger, GIDFlowName) { /// The Sign In flow. GIDFlowNameSignIn = 0, /// The Verify flow. - GIDFlowNameVerify = 1, + GIDFlowNameVerifyAccountDetail = 1, }; @protocol GIDAuthorizationResponseHandling diff --git a/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m b/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m index fbae509c..6f4b8fcd 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthFlowTest.m @@ -35,10 +35,10 @@ - (void)testInitWithAuthState { profileData:profileData]; XCTAssertNotNil(authFlow); - XCTAssertNotNil(authFlow.authState); + XCTAssertEqual(authFlow.authState, authState); XCTAssertNil(authFlow.error); XCTAssertNil(authFlow.emmSupport); - XCTAssertNotNil(authFlow.profileData); + XCTAssertEqual(authFlow.profileData, profileData); } - (void)testInit { diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 1d99c228..34b6a3be 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -26,10 +26,14 @@ #import "GoogleSignIn/Tests/Unit/OIDAuthorizationResponse+Testing.h" #import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" +#import "GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h" // The EMM support version static NSString *const kEMMVersion = @"1"; +// Time interval to use for an expiring access token. +static NSTimeInterval kExpiringAccessToken = 20; + @interface GIDAuthorizationResponseHelperTest : XCTestCase @end @@ -39,7 +43,7 @@ - (void)testInitWithAuthorizationResponseHandler { GIDAuthorizationResponseHandler *responseHandler = [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil emmSupport:nil - flowName:GIDFlowNameVerify + flowName:GIDFlowNameVerifyAccountDetail configuration:nil error:nil]; GIDAuthorizationResponseHelper *responseHelper = @@ -50,36 +54,41 @@ - (void)testInitWithAuthorizationResponseHandler { } - (void)testFetchTokenWithAuthFlow { - OIDAuthState *authState = [OIDAuthState testInstance]; - GIDAuthorizationResponseHandlingFake *fakeHandler = + OIDTokenResponse *tokenResponse = + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; + + GIDAuthorizationResponseHandlingFake *responseHandler = [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthorizationResponseHelper *responseHelper = - [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:fakeHandler]; - GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] init]; + [[GIDAuthorizationResponseHelper alloc] initWithAuthorizationResponseHandler:responseHandler]; + GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState + error:nil + emmSupport:nil + profileData:nil]; [responseHelper fetchTokenWithAuthFlow:authFlow]; XCTAssertNotNil(authFlow); - XCTAssertNotNil(authFlow.authState); + XCTAssertEqual(authFlow.authState, authState); XCTAssertNil(authFlow.error); } - (void)testSuccessfulGenerateAuthFlowFromAuthorizationResponse { - OIDAuthorizationResponse *authorizationResponse = [OIDAuthorizationResponse testInstance]; - GIDAuthorizationResponseHandler *responseHandler = - [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse - emmSupport:nil - flowName:GIDFlowNameVerify - configuration:nil - error:nil]; + OIDTokenResponse *tokenResponse = + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; + + GIDAuthorizationResponseHandlingFake *responseHandler = + [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthFlow *authFlow = [responseHandler generateAuthFlowFromAuthorizationResponse]; XCTAssertNotNil(authFlow); - XCTAssertNotNil(authFlow.authState); + XCTAssertEqual(authFlow.authState, authState); XCTAssertNil(authFlow.error); } -- (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST +- (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : @"Unknown error" }; NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain @@ -92,7 +101,7 @@ - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { GIDAuthorizationResponseHandler *responseHandler = [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:authorizationResponse emmSupport:nil - flowName:GIDFlowNameVerify + flowName:GIDFlowNameVerifyAccountDetail configuration:nil error:nil]; @@ -100,21 +109,28 @@ - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); + XCTAssertEqual(authFlow.error.domain, expectedError.domain); XCTAssertEqual(authFlow.error.code, expectedError.code); - XCTAssertEqualObjects(authFlow.error.userInfo[NSLocalizedDescriptionKey], - expectedError.userInfo[NSLocalizedDescriptionKey]); -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + XCTAssertEqualObjects(authFlow.error.userInfo, expectedError.userInfo); } +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST -- (void)testGenerateAuthFlowWithMissingAuthorizationResponse { #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST +- (void)testGenerateAuthFlowWithMissingAuthorizationResponse { NSError *error = [NSError errorWithDomain:kGIDVerifyErrorDomain code:GIDVerifyErrorCodeUnknown userInfo:nil]; + + NSString *errorString = [error localizedDescription]; + NSDictionary *errorDict = @{ NSLocalizedDescriptionKey : errorString }; + NSError *expectedError = [NSError errorWithDomain:kGIDVerifyErrorDomain + code:GIDVerifyErrorCodeUnknown + userInfo:errorDict]; + GIDAuthorizationResponseHandler *responseHandler = [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil emmSupport:nil - flowName:GIDFlowNameVerify + flowName:GIDFlowNameVerifyAccountDetail configuration:nil error:error]; @@ -122,48 +138,52 @@ - (void)testGenerateAuthFlowWithMissingAuthorizationResponse { XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error.code, error.code); -#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + XCTAssertEqual(authFlow.error.domain, expectedError.domain); + XCTAssertEqual(authFlow.error.code, expectedError.code); + XCTAssertEqualObjects(authFlow.error.userInfo, expectedError.userInfo); } +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST -- (void)testMaybeFetchTokenWithAuthFlowError { +- (void)testMaybeFetchToken_authFlowError { NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain code:kGIDSignInErrorCodeUnknown userInfo:nil]; + + OIDTokenResponse *tokenResponse = + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; + + GIDAuthorizationResponseHandlingFake *responseHandler = + [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:nil error:error emmSupport:nil profileData:nil]; - GIDAuthorizationResponseHandler *responseHandler = - [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil - emmSupport:kEMMVersion - flowName:GIDFlowNameSignIn - configuration:nil - error:nil]; [responseHandler maybeFetchToken:authFlow]; XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertNil(authFlow.emmSupport); + XCTAssertEqual(authFlow.error, error); } -- (void)testMaybeFetchTokenWithExpirationError { +- (void)testMaybeFetchToken_noRefresh { + NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain + code:kGIDSignInErrorCodeUnknown + userInfo:nil]; + OIDAuthState *authState = [OIDAuthState testInstance]; + GIDAuthorizationResponseHandlingFake *responseHandler = + [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState - error:nil + error:error emmSupport:nil profileData:nil]; - GIDAuthorizationResponseHandler *responseHandler = - [[GIDAuthorizationResponseHandler alloc] initWithAuthorizationResponse:nil - emmSupport:kEMMVersion - flowName:GIDFlowNameSignIn - configuration:nil - error:nil]; [responseHandler maybeFetchToken:authFlow]; XCTAssertNotNil(authFlow.authState); - XCTAssertNil(authFlow.error); - XCTAssertNil(authFlow.emmSupport); + XCTAssertEqual(authFlow.authState, authState); + XCTAssertNotNil(authFlow.error); + XCTAssertEqual(authFlow.error, error); } @end diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h index b565a392..16f8b80f 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h @@ -53,6 +53,8 @@ extern NSString * const kFatPictureURL; + (instancetype)testInstanceWithIDToken:(NSString *)idToken; ++ (instancetype)testInstanceWithAccessTokenExpiresIn:(NSNumber *)accessTokenExpiresIn; + + (instancetype)testInstanceWithIDToken:(NSString *)idToken accessToken:(NSString *)accessToken expiresIn:(NSNumber *)expiresIn diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m index 49823be7..dd7efb2e 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m @@ -65,6 +65,14 @@ + (instancetype)testInstanceWithIDToken:(NSString *)idToken { tokenRequest:nil]; } ++ (instancetype)testInstanceWithAccessTokenExpiresIn:(NSNumber *)accessTokenExpiresIn { + return [OIDTokenResponse testInstanceWithIDToken:[self idToken] + accessToken:nil + expiresIn:accessTokenExpiresIn + refreshToken:nil + tokenRequest:nil]; +} + + (instancetype)testInstanceWithIDToken:(NSString *)idToken accessToken:(NSString *)accessToken expiresIn:(NSNumber *)expiresIn From caab226b6724d319031b5bd961d7ab5c06b53016 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 3 Jun 2024 17:30:41 -0700 Subject: [PATCH 52/55] Import OIDTokenResponse. --- .../Fake/GIDAuthorizationResponseHandlingFake.m | 1 + 1 file changed, 1 insertion(+) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m index f8af5216..f10bdd66 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Fake/GIDAuthorizationResponseHandlingFake.m @@ -25,6 +25,7 @@ @import AppAuth; #else #import +#import #endif @implementation GIDAuthorizationResponseHandlingFake From 0caef48de7cf0fae83ff8ebba1b8068a2fa8aee3 Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 3 Jun 2024 17:56:23 -0700 Subject: [PATCH 53/55] Use created expiring access token time interval. --- .../Tests/Unit/GIDAuthorizationResponseHelperTest.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 34b6a3be..8b83383c 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -55,7 +55,7 @@ - (void)testInitWithAuthorizationResponseHandler { - (void)testFetchTokenWithAuthFlow { OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = @@ -75,7 +75,7 @@ - (void)testFetchTokenWithAuthFlow { - (void)testSuccessfulGenerateAuthFlowFromAuthorizationResponse { OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = @@ -150,7 +150,7 @@ - (void)testMaybeFetchToken_authFlowError { userInfo:nil]; OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kAccessTokenExpiresIn)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = From f5d431575b5d938e2939c57aec540598200ba6cb Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 4 Jun 2024 22:49:47 -0700 Subject: [PATCH 54/55] Update doc comments and naming. --- .../API/GIDAuthorizationResponseHandling.h | 4 +-- .../GIDAuthorizationResponseHandler.h | 2 +- .../GIDAuthorizationResponseHandler.m | 5 ++-- .../Unit/GIDAuthorizationResponseHelperTest.m | 26 ++++++++----------- .../Tests/Unit/OIDTokenResponse+Testing.h | 2 +- .../Tests/Unit/OIDTokenResponse+Testing.m | 4 +-- 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h index 2f2bfe22..ddd362af 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/API/GIDAuthorizationResponseHandling.h @@ -24,9 +24,9 @@ NS_ASSUME_NONNULL_BEGIN /// A list of potential current flow names. typedef NS_ENUM(NSInteger, GIDFlowName) { -/// The Sign In flow. + /// The Sign In flow. GIDFlowNameSignIn = 0, -/// The Verify flow. + /// The Verify flow. GIDFlowNameVerifyAccountDetail = 1, }; diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h index de2b79a6..523d8852 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN -/// A class that handles the authorization response and fetch tokens. +/// A class that handles the authorization response and fetches tokens. @interface GIDAuthorizationResponseHandler : NSObject @end diff --git a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m index 11122023..832ea3e9 100644 --- a/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m +++ b/GoogleSignIn/Sources/GIDAuthorizationResponse/Implementations/GIDAuthorizationResponseHandler.m @@ -92,8 +92,7 @@ - (GIDAuthFlow *)generateAuthFlowFromAuthorizationResponse { [self authorizationCodeErrorToAuthFlow:authFlow]; } } else { - [self authorizationResponseErrorToAuthFlow:authFlow - error:_error]; + [self authorizationResponseErrorToAuthFlow:authFlow error:_error]; } return authFlow; } @@ -175,7 +174,7 @@ - (void)authorizationCodeErrorToAuthFlow:(GIDAuthFlow *)authFlow { if (authFlow.emmSupport) { [authFlow wait]; BOOL isEMMError = [[GIDEMMErrorHandler sharedInstance] - handleErrorFromResponse:params + handleErrorFromResponse:params completion:^{ [authFlow next]; }]; diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 8b83383c..7f0953be 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -28,11 +28,11 @@ #import "GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h" #import "GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h" -// The EMM support version +/// The EMM support version static NSString *const kEMMVersion = @"1"; -// Time interval to use for an expiring access token. -static NSTimeInterval kExpiringAccessToken = 20; +/// Time interval to use for an expiring access token. +static NSTimeInterval kAccessTokenExpiration = 20; @interface GIDAuthorizationResponseHelperTest : XCTestCase @end @@ -55,7 +55,7 @@ - (void)testInitWithAuthorizationResponseHandler { - (void)testFetchTokenWithAuthFlow { OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiration:@(kAccessTokenExpiration)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = @@ -75,7 +75,7 @@ - (void)testFetchTokenWithAuthFlow { - (void)testSuccessfulGenerateAuthFlowFromAuthorizationResponse { OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiration:@(kAccessTokenExpiration)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = @@ -109,9 +109,7 @@ - (void)testGenerateAuthFlowFromAuthorizationResponse_noCode { XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error.domain, expectedError.domain); - XCTAssertEqual(authFlow.error.code, expectedError.code); - XCTAssertEqualObjects(authFlow.error.userInfo, expectedError.userInfo); + XCTAssertEqualObjects(authFlow.error, expectedError); } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -138,9 +136,7 @@ - (void)testGenerateAuthFlowWithMissingAuthorizationResponse { XCTAssertNotNil(authFlow); XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error.domain, expectedError.domain); - XCTAssertEqual(authFlow.error.code, expectedError.code); - XCTAssertEqualObjects(authFlow.error.userInfo, expectedError.userInfo); + XCTAssertEqualObjects(authFlow.error, expectedError); } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST @@ -150,7 +146,7 @@ - (void)testMaybeFetchToken_authFlowError { userInfo:nil]; OIDTokenResponse *tokenResponse = - [OIDTokenResponse testInstanceWithAccessTokenExpiresIn:@(kExpiringAccessToken)]; + [OIDTokenResponse testInstanceWithAccessTokenExpiration:@(kAccessTokenExpiration)]; OIDAuthState *authState = [OIDAuthState testInstanceWithTokenResponse:tokenResponse]; GIDAuthorizationResponseHandlingFake *responseHandler = @@ -163,7 +159,7 @@ - (void)testMaybeFetchToken_authFlowError { [responseHandler maybeFetchToken:authFlow]; XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error, error); + XCTAssertEqualObjects(authFlow.error, error); } - (void)testMaybeFetchToken_noRefresh { @@ -181,9 +177,9 @@ - (void)testMaybeFetchToken_noRefresh { [responseHandler maybeFetchToken:authFlow]; XCTAssertNotNil(authFlow.authState); - XCTAssertEqual(authFlow.authState, authState); + XCTAssertEqualObjects(authFlow.authState, authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqual(authFlow.error, error); + XCTAssertEqualObjects(authFlow.error, error); } @end diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h index 16f8b80f..2bff75ef 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h @@ -53,7 +53,7 @@ extern NSString * const kFatPictureURL; + (instancetype)testInstanceWithIDToken:(NSString *)idToken; -+ (instancetype)testInstanceWithAccessTokenExpiresIn:(NSNumber *)accessTokenExpiresIn; ++ (instancetype)testInstanceWithAccessTokenExpiration:(NSNumber *)expiration; + (instancetype)testInstanceWithIDToken:(NSString *)idToken accessToken:(NSString *)accessToken diff --git a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m index dd7efb2e..45b0e77e 100644 --- a/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m +++ b/GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m @@ -65,10 +65,10 @@ + (instancetype)testInstanceWithIDToken:(NSString *)idToken { tokenRequest:nil]; } -+ (instancetype)testInstanceWithAccessTokenExpiresIn:(NSNumber *)accessTokenExpiresIn { ++ (instancetype)testInstanceWithAccessTokenExpiration:(NSNumber *)expiration { return [OIDTokenResponse testInstanceWithIDToken:[self idToken] accessToken:nil - expiresIn:accessTokenExpiresIn + expiresIn:expiration refreshToken:nil tokenRequest:nil]; } From 77aea79eefada77035ffe3e0978291ec7c06f742 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 5 Jun 2024 10:46:32 -0700 Subject: [PATCH 55/55] Changed variable names from "error" to "expectedError". --- .../Unit/GIDAuthorizationResponseHelperTest.m | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m index 7f0953be..038413b9 100644 --- a/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m +++ b/GoogleSignIn/Tests/Unit/GIDAuthorizationResponseHelperTest.m @@ -141,9 +141,9 @@ - (void)testGenerateAuthFlowWithMissingAuthorizationResponse { #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)testMaybeFetchToken_authFlowError { - NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeUnknown - userInfo:nil]; + NSError *expectedError = [NSError errorWithDomain:kGIDSignInErrorDomain + code:kGIDSignInErrorCodeUnknown + userInfo:nil]; OIDTokenResponse *tokenResponse = [OIDTokenResponse testInstanceWithAccessTokenExpiration:@(kAccessTokenExpiration)]; @@ -152,26 +152,26 @@ - (void)testMaybeFetchToken_authFlowError { GIDAuthorizationResponseHandlingFake *responseHandler = [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:nil - error:error + error:expectedError emmSupport:nil profileData:nil]; [responseHandler maybeFetchToken:authFlow]; XCTAssertNil(authFlow.authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqualObjects(authFlow.error, error); + XCTAssertEqualObjects(authFlow.error, expectedError); } - (void)testMaybeFetchToken_noRefresh { - NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeUnknown - userInfo:nil]; + NSError *expectedError = [NSError errorWithDomain:kGIDSignInErrorDomain + code:kGIDSignInErrorCodeUnknown + userInfo:nil]; OIDAuthState *authState = [OIDAuthState testInstance]; GIDAuthorizationResponseHandlingFake *responseHandler = [[GIDAuthorizationResponseHandlingFake alloc] initWithAuthState:authState error:nil]; GIDAuthFlow *authFlow = [[GIDAuthFlow alloc] initWithAuthState:authState - error:error + error:expectedError emmSupport:nil profileData:nil]; @@ -179,7 +179,7 @@ - (void)testMaybeFetchToken_noRefresh { XCTAssertNotNil(authFlow.authState); XCTAssertEqualObjects(authFlow.authState, authState); XCTAssertNotNil(authFlow.error); - XCTAssertEqualObjects(authFlow.error, error); + XCTAssertEqualObjects(authFlow.error, expectedError); } @end