From d8e707dc066e2a2a1aa4194e9067da85a55fbb18 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 14 Oct 2022 15:55:30 -0700 Subject: [PATCH 01/13] Move the method `addScopes` into GIDGoogleUser API --- GoogleSignIn/Sources/GIDGoogleUser.m | 25 +++++++++++ GoogleSignIn/Sources/GIDSignIn_Private.h | 45 +++++++++++++++++++ .../Public/GoogleSignIn/GIDGoogleUser.h | 45 +++++++++++++++++++ .../Sources/Public/GoogleSignIn/GIDSignIn.h | 31 ------------- .../Source/SignInViewController.m | 11 ++--- .../Services/GoogleSignInAuthenticator.swift | 5 ++- 6 files changed, 124 insertions(+), 38 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 0c18a49e..ea3faca2 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -17,6 +17,7 @@ #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/GIDSignIn_Private.h" #import "GoogleSignIn/Sources/GIDAppAuthFetcherAuthorizationWithEMMSupport.h" #import "GoogleSignIn/Sources/GIDAuthentication.h" @@ -181,6 +182,30 @@ - (OIDAuthState *) authState{ return ((GTMAppAuthFetcherAuthorization *)self.fetcherAuthorizer).authState; } +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +- (void)addScopes:(NSArray *)scopes + presentingViewController:(UIViewController *)presentingViewController + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { + [[GIDSignIn sharedInstance] addScopes:scopes + presentingViewController:presentingViewController + completion:completion]; +} + +#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST + +- (void)addScopes:(NSArray *)scopes + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { + [[GIDSignIn sharedInstance] addScopes:scopes + presentingViewController:presentingWindow + completion:completion]; +} + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + #pragma mark - Private Methods #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 190a629c..68abf0a5 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -14,8 +14,16 @@ * limitations under the License. */ +#import + #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" +#if __has_include() +#import +#elif __has_include() +#import +#endif + NS_ASSUME_NONNULL_BEGIN @class GIDGoogleUser; @@ -44,6 +52,43 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * // @return NO if there is no user restored from the keychain. - (BOOL)restorePreviousSignInNoRefresh; +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + +// Starts an interactive consent flow on iOS to add scopes to the current user's grants. +// +// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +// +// @param scopes The scopes to ask the user to consent to. +// @param presentingViewController The view controller used to present `SFSafariViewContoller` on +// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on +// iOS 13+. +// @param completion The block that is called on completion. This block will be called asynchronously +// on the main queue. +- (void)addScopes:(NSArray *)scopes + presentingViewController:(UIViewController *)presentingViewController + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion + NS_EXTENSION_UNAVAILABLE("The add scopes flow is not supported in App Extensions."); + +#elif TARGET_OS_OSX + +// Starts an interactive consent flow on macOS to add scopes to the current user's grants +// +// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +// +// @param scopes An array of scopes to ask the user to consent to. +// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. +// @param completion The block that is called on completion. This block will be called asynchronously +// on the main queue. +- (void)addScopes:(NSArray *)scopes + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; + +#endif + @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index 558d9a9f..b5ede573 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -15,6 +15,13 @@ */ #import +#import + +#if __has_include() +#import +#elif __has_include() +#import +#endif // We have to import GTMAppAuth because forward declaring the protocol does // not generate the `fetcherAuthorizer` property below for Swift. @@ -25,6 +32,7 @@ #endif @class GIDConfiguration; +@class GIDUserAuth; @class GIDToken; @class GIDProfileData; @@ -71,6 +79,43 @@ NS_ASSUME_NONNULL_BEGIN - (void)doWithFreshTokens:(void (^)(GIDGoogleUser *_Nullable user, NSError *_Nullable error))completion; +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + +/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. +/// +/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +/// +/// @param scopes The scopes to ask the user to consent to. +/// @param presentingViewController The view controller used to present `SFSafariViewContoller` on +/// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on +/// iOS 13+. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. +- (void)addScopes:(NSArray *)scopes + presentingViewController:(UIViewController *)presentingViewController + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion + NS_EXTENSION_UNAVAILABLE("The add scopes flow is not supported in App Extensions."); + +#elif TARGET_OS_OSX + +/// Starts an interactive consent flow on macOS to add scopes to the current user's grants. +/// +/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +/// +/// @param scopes An array of scopes to ask the user to consent to. +/// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. +- (void)addScopes:(NSArray *)scopes + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; + +#endif + @end NS_ASSUME_NONNULL_END diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 8fad0549..7f602459 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -165,23 +165,6 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion; -/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. -/// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` -/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. -/// -/// @param scopes The scopes to ask the user to consent to. -/// @param presentingViewController The view controller used to present `SFSafariViewContoller` on -/// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on -/// iOS 13+. -/// @param completion The block that is called on completion. This block will be called asynchronously -/// on the main queue. -- (void)addScopes:(NSArray *)scopes - presentingViewController:(UIViewController *)presentingViewController - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion - NS_EXTENSION_UNAVAILABLE("The add scopes flow is not supported in App Extensions."); - #elif TARGET_OS_OSX /// Starts an interactive sign-in flow on macOS. /// @@ -233,20 +216,6 @@ typedef void (^GIDDisconnectCompletion)(NSError *_Nullable error); completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion; -/// Starts an interactive consent flow on macOS to add scopes to the current user's grants. -/// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` -/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. -/// -/// @param scopes An array of scopes to ask the user to consent to. -/// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. -/// @param completion The block that is called on completion. This block will be called asynchronously -/// on the main queue. -- (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion; - #endif @end diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index e2b3d077..8524bb26 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -248,7 +248,7 @@ - (void)updateButtons { - (IBAction)signIn:(id)sender { [GIDSignIn.sharedInstance signInWithPresentingViewController:self - completion:^(GIDGoogleUser *user, + completion:^(GIDUserAuth *userAuth, NSError *error) { if (error) { self->_signInAuthStatus.text = @@ -280,10 +280,11 @@ - (IBAction)disconnect:(id)sender { } - (IBAction)addScopes:(id)sender { - [GIDSignIn.sharedInstance addScopes:@[ @"https://www.googleapis.com/auth/user.birthday.read" ] - presentingViewController:self - completion:^(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error) { + GIDGoogleUser *currentUser = GIDSignIn.sharedInstance.currentUser; + [currentUser addScopes:@[ @"https://www.googleapis.com/auth/user.birthday.read" ] + presentingViewController:self + completion:^(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Failed to add scopes: %@", error]; diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index ce20106f..acf788c5 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -88,8 +88,9 @@ final class GoogleSignInAuthenticator: ObservableObject { fatalError("No root view controller!") } - GIDSignIn.sharedInstance.addScopes([BirthdayLoader.birthdayReadScope], - presenting: rootViewController) { userAuth, error in + GIDSignIn.sharedInstance.currentUser?.addScopes( + [BirthdayLoader.birthdayReadScope], presenting: rootViewController) + { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return From ba4095f60917f4d47d378e47e0161942335ce052 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 14 Oct 2022 16:51:03 -0700 Subject: [PATCH 02/13] Minor improvement --- GoogleSignIn/Sources/GIDGoogleUser.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index ea3faca2..6246b366 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -17,12 +17,12 @@ #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" -#import "GoogleSignIn/Sources/GIDSignIn_Private.h" #import "GoogleSignIn/Sources/GIDAppAuthFetcherAuthorizationWithEMMSupport.h" #import "GoogleSignIn/Sources/GIDAuthentication.h" #import "GoogleSignIn/Sources/GIDEMMSupport.h" #import "GoogleSignIn/Sources/GIDProfileData_Private.h" +#import "GoogleSignIn/Sources/GIDSignIn_Private.h" #import "GoogleSignIn/Sources/GIDSignInPreferences.h" #import "GoogleSignIn/Sources/GIDToken_Private.h" @@ -188,9 +188,9 @@ - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion { - [[GIDSignIn sharedInstance] addScopes:scopes - presentingViewController:presentingViewController - completion:completion]; + [GIDSignIn.sharedInstance addScopes:scopes + presentingViewController:presentingViewController + completion:completion]; } #elif TARGET_OS_OSX || TARGET_OS_MACCATALYST @@ -199,9 +199,9 @@ - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion { - [[GIDSignIn sharedInstance] addScopes:scopes - presentingViewController:presentingWindow - completion:completion]; + [GIDSignIn.sharedInstance addScopes:scopes + presentingViewController:presentingWindow + completion:completion]; } #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST From 3d0f25dd476e3bf89e2c41961875907cba47e7a1 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 17 Oct 2022 10:56:36 -0700 Subject: [PATCH 03/13] Fix typo --- GoogleSignIn/Sources/GIDGoogleUser.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 6246b366..8b70277f 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -200,7 +200,7 @@ - (void)addScopes:(NSArray *)scopes completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion { [GIDSignIn.sharedInstance addScopes:scopes - presentingViewController:presentingWindow + presentingWindow:presentingWindow completion:completion]; } From c5a6797ea0580f7ca7bdf050527f7004b636fed5 Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 17 Oct 2022 11:36:22 -0700 Subject: [PATCH 04/13] Fix Demo app and improve style --- GoogleSignIn/Sources/GIDSignIn_Private.h | 4 ++-- .../ObjC/SignInSample/Source/SignInViewController.m | 4 ++-- .../Shared/Services/GoogleSignInAuthenticator.swift | 11 ++++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 68abf0a5..0362d185 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -83,8 +83,8 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * // @param completion The block that is called on completion. This block will be called asynchronously // on the main queue. - (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion; #endif diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index 8524bb26..038f754a 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -282,8 +282,8 @@ - (IBAction)disconnect:(id)sender { - (IBAction)addScopes:(id)sender { GIDGoogleUser *currentUser = GIDSignIn.sharedInstance.currentUser; [currentUser addScopes:@[ @"https://www.googleapis.com/auth/user.birthday.read" ] - presentingViewController:self - completion:^(GIDUserAuth *_Nullable userAuth, + presentingViewController:self + completion:^(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Failed to add scopes: %@", diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index acf788c5..73d04866 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -83,14 +83,15 @@ final class GoogleSignInAuthenticator: ObservableObject { /// - note: Successful requests will update the `authViewModel.state` with a new current user that /// has the granted scope. func addBirthdayReadScope(completion: @escaping () -> Void) { + let currentUser = GIDSignIn.sharedInstance.currentUser + #if os(iOS) guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { fatalError("No root view controller!") } - GIDSignIn.sharedInstance.currentUser?.addScopes( - [BirthdayLoader.birthdayReadScope], presenting: rootViewController) - { userAuth, error in + currentUser?.addScopes([BirthdayLoader.birthdayReadScope], + presenting: rootViewController) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return @@ -106,8 +107,8 @@ final class GoogleSignInAuthenticator: ObservableObject { fatalError("No presenting window!") } - GIDSignIn.sharedInstance.addScopes([BirthdayLoader.birthdayReadScope], - presenting: presentingWindow) { userAuth, error in + currentUser?.addScopes([BirthdayLoader.birthdayReadScope], + presenting: presentingWindow) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return From e07017284885d948031e01ccef3ae6331e2dda8a Mon Sep 17 00:00:00 2001 From: pinlu Date: Mon, 17 Oct 2022 16:11:00 -0700 Subject: [PATCH 05/13] Fix Indentation --- .../Shared/Services/GoogleSignInAuthenticator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 73d04866..65b2ae51 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -108,7 +108,7 @@ final class GoogleSignInAuthenticator: ObservableObject { } currentUser?.addScopes([BirthdayLoader.birthdayReadScope], - presenting: presentingWindow) { userAuth, error in + presenting: presentingWindow) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return From f4dd91bb6702a85aeddb966e5475b1ff0f3d2908 Mon Sep 17 00:00:00 2001 From: pinlu Date: Tue, 18 Oct 2022 14:56:26 -0700 Subject: [PATCH 06/13] Update documentation in GIDSignIn_Private.h to make it viewable in Xcode Replace `//` with `///` --- GoogleSignIn/Sources/GIDSignIn_Private.h | 61 ++++++++++++------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 0362d185..07d24000 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -29,42 +29,42 @@ NS_ASSUME_NONNULL_BEGIN @class GIDGoogleUser; @class GIDSignInInternalOptions; -// Represents a completion block that takes a `GIDUserAuth` on success or an error if the operation -// was unsuccessful. +/// Represents a completion block that takes a `GIDUserAuth` on success or an error if the operation +/// was unsuccessful. typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error); // Private |GIDSignIn| methods that are used internally in this SDK and other Google SDKs. @interface GIDSignIn () -// Redeclare |currentUser| as readwrite for internal use. +/// Redeclare |currentUser| as readwrite for internal use. @property(nonatomic, readwrite, nullable) GIDGoogleUser *currentUser; -// Private initializer for |GIDSignIn|. +/// Private initializer for |GIDSignIn|. - (instancetype)initPrivate; -// Authenticates with extra options. +/// Authenticates with extra options. - (void)signInWithOptions:(GIDSignInInternalOptions *)options; -// Restores a previously authenticated user from the keychain synchronously without refreshing -// the access token or making a userinfo request. The currentUser.profile will be nil unless -// the profile data can be extracted from the ID token. -// -// @return NO if there is no user restored from the keychain. +/// Restores a previously authenticated user from the keychain synchronously without refreshing +/// the access token or making a userinfo request. The currentUser.profile will be nil unless +/// the profile data can be extracted from the ID token. +/// +/// @return NO if there is no user restored from the keychain. - (BOOL)restorePreviousSignInNoRefresh; #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -// Starts an interactive consent flow on iOS to add scopes to the current user's grants. -// -// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` -// instance will be returned reflecting the new scopes and saved sign-in state will be updated. -// -// @param scopes The scopes to ask the user to consent to. -// @param presentingViewController The view controller used to present `SFSafariViewContoller` on -// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on -// iOS 13+. -// @param completion The block that is called on completion. This block will be called asynchronously -// on the main queue. +/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. +/// +/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +/// +/// @param scopes The scopes to ask the user to consent to. +/// @param presentingViewController The view controller used to present `SFSafariViewContoller` on +/// iOS 9 and 10 and to supply `presentationContextProvider` for `ASWebAuthenticationSession` on +/// iOS 13+. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, @@ -73,15 +73,16 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * #elif TARGET_OS_OSX -// Starts an interactive consent flow on macOS to add scopes to the current user's grants -// -// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` -// instance will be returned reflecting the new scopes and saved sign-in state will be updated. -// -// @param scopes An array of scopes to ask the user to consent to. -// @param presentingWindow The window used to supply `presentationContextProvider` for `ASWebAuthenticationSession`. -// @param completion The block that is called on completion. This block will be called asynchronously -// on the main queue. +/// Starts an interactive consent flow on macOS to add scopes to the current user's grants +/// +/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// instance will be returned reflecting the new scopes and saved sign-in state will be updated. +/// +/// @param scopes An array of scopes to ask the user to consent to. +/// @param presentingWindow The window used to supply `presentationContextProvider` for +/// `ASWebAuthenticationSession`. +/// @param completion The block that is called on completion. This block will be called asynchronously +/// on the main queue. - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, From 32ba6faee83a11514da99857de078f049283d620 Mon Sep 17 00:00:00 2001 From: pinlu Date: Tue, 18 Oct 2022 17:33:46 -0700 Subject: [PATCH 07/13] Improve documentation --- GoogleSignIn/Sources/GIDSignIn_Private.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 07d24000..12c082b5 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -46,8 +46,9 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * - (void)signInWithOptions:(GIDSignInInternalOptions *)options; /// Restores a previously authenticated user from the keychain synchronously without refreshing -/// the access token or making a userinfo request. The currentUser.profile will be nil unless -/// the profile data can be extracted from the ID token. +/// the access token or making a userinfo request. +/// +/// The currentUser.profile will be nil unless the profile data can be extracted from the ID token. /// /// @return NO if there is no user restored from the keychain. - (BOOL)restorePreviousSignInNoRefresh; From 8c4d95453e2e826641d8c875cbdb850c07a06f47 Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 20 Oct 2022 16:10:22 -0700 Subject: [PATCH 08/13] Resolved comments --- GoogleSignIn/Sources/GIDGoogleUser.m | 32 +++++--- GoogleSignIn/Sources/GIDSignIn_Private.h | 10 +-- .../Public/GoogleSignIn/GIDGoogleUser.h | 14 ++-- .../Sources/Public/GoogleSignIn/GIDSignIn.h | 4 +- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 75 +++++++++++++++++++ .../Services/GoogleSignInAuthenticator.swift | 10 ++- 6 files changed, 118 insertions(+), 27 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index 8b70277f..fa028a03 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -17,6 +17,7 @@ #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" #import "GoogleSignIn/Sources/GIDAppAuthFetcherAuthorizationWithEMMSupport.h" #import "GoogleSignIn/Sources/GIDAuthentication.h" @@ -183,28 +184,39 @@ - (OIDAuthState *) authState{ } #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error))completion { +#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST +- (void)addScopes:(NSArray *)scopes + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + + if (self != GIDSignIn.sharedInstance.currentUser) { + NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain + code:kGIDSignInErrorCodePreviousUser + userInfo:nil]; + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil, error); + }); + } + return; + } + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST [GIDSignIn.sharedInstance addScopes:scopes presentingViewController:presentingViewController completion:completion]; -} - #elif TARGET_OS_OSX || TARGET_OS_MACCATALYST - -- (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion { [GIDSignIn.sharedInstance addScopes:scopes presentingWindow:presentingWindow completion:completion]; -} - #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST +} #pragma mark - Private Methods diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 12c082b5..76907568 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -55,9 +55,9 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. +/// Starts an interactive consent flow on iOS to add scopes to the user's grants. /// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. /// /// @param scopes The scopes to ask the user to consent to. @@ -74,9 +74,9 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * #elif TARGET_OS_OSX -/// Starts an interactive consent flow on macOS to add scopes to the current user's grants +/// Starts an interactive consent flow on macOS to add scopes to the user's grants /// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. /// /// @param scopes An array of scopes to ask the user to consent to. @@ -87,7 +87,7 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion; + NSError *_Nullable error))completion; #endif diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h index b5ede573..ee080a27 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h @@ -81,9 +81,9 @@ NS_ASSUME_NONNULL_BEGIN #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. +/// Starts an interactive consent flow on iOS to add scopes to the user's grants. /// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. /// /// @param scopes The scopes to ask the user to consent to. @@ -100,9 +100,9 @@ NS_ASSUME_NONNULL_BEGIN #elif TARGET_OS_OSX -/// Starts an interactive consent flow on macOS to add scopes to the current user's grants. +/// Starts an interactive consent flow on macOS to add scopes to the user's grants. /// -/// The completion will be called at the end of this process. If successful, a new `GIDGoogleUser` +/// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. /// /// @param scopes An array of scopes to ask the user to consent to. @@ -110,9 +110,9 @@ NS_ASSUME_NONNULL_BEGIN /// @param completion The block that is called on completion. This block will be called asynchronously /// on the main queue. - (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion; + presentingWindow:(NSWindow *)presentingWindow + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion; #endif diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 7f602459..2d020fc0 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -47,8 +47,10 @@ typedef NS_ERROR_ENUM(kGIDSignInErrorDomain, GIDSignInErrorCode) { kGIDSignInErrorCodeEMM = -6, /// Indicates there is no `currentUser`. kGIDSignInErrorCodeNoCurrentUser = -7, + /// Indicates there is an operation on a previous user. + kGIDSignInErrorCodePreviousUser = -8, /// Indicates the requested scopes have already been granted to the `currentUser`. - kGIDSignInErrorCodeScopesAlreadyGranted = -8, + kGIDSignInErrorCodeScopesAlreadyGranted = -9, }; /// Represents a completion block that takes an error if the operation was unsuccessful. diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 488d3f63..460350dd 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -15,9 +15,11 @@ #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDGoogleUser.h" #import +#import #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDProfileData.h" +#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h" #import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDToken.h" #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h" @@ -33,6 +35,7 @@ @import GoogleUtilities_MethodSwizzler; @import GoogleUtilities_SwizzlerTestHelpers; @import GTMAppAuth; +@import OCMock; #else #import #import @@ -45,6 +48,7 @@ #import #import #import +#import #endif static NSString *const kNewAccessToken = @"new_access_token"; @@ -54,6 +58,8 @@ static NSTimeInterval const kIDTokenExpiresIn = 100; static NSTimeInterval const kNewIDTokenExpiresIn = 200; +static NSString *const kNewScope = @"newScope"; + @interface GIDGoogleUserTest : XCTestCase @end @@ -437,6 +443,75 @@ - (void)testDoWithFreshTokens_handleConcurrentRefresh { [self waitForExpectationsWithTimeout:1 handler:nil]; } +- (void)testAddScopes_success { + id signIn = OCMClassMock([GIDSignIn class]); + OCMStub([signIn sharedInstance]).andReturn(signIn); + [[signIn expect] addScopes:OCMOCK_ANY +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + presentingViewController:OCMOCK_ANY +#elif TARGET_OS_OSX + presentingWindow:OCMOCK_ANY +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + completion:OCMOCK_ANY]; + + GIDGoogleUser *currentUser = [self googleUserWithAccessTokenExpiresIn:kAccessTokenExpiresIn + idTokenExpiresIn:kIDTokenExpiresIn]; + + OCMStub([signIn currentUser]).andReturn(currentUser); + +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + UIViewController *presentingViewController = [[UIViewController alloc] init]; + [currentUser addScopes:@[kNewScope] + presentingViewController:presentingViewController + completion:nil]; +#elif TARGET_OS_OSX + NSWindow *presentingWindow = [[NSWindow alloc] init]; + [currentUser addScopes:@[kNewScope] + presentingWindow:presentingWindow + completion:nil]; +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + + [signIn verify]; +} + +- (void)testAddScopes_failure_addScopesToPreviousAccount { + id signIn = OCMClassMock([GIDSignIn class]); + OCMStub([signIn sharedInstance]).andReturn(signIn); + + GIDGoogleUser *currentUser = [self googleUserWithAccessTokenExpiresIn:kAccessTokenExpiresIn + idTokenExpiresIn:kIDTokenExpiresIn]; + + OCMStub([signIn currentUser]).andReturn(currentUser); + + GIDGoogleUser *previousUser = [self googleUserWithAccessTokenExpiresIn:kAccessTokenExpiresIn + idTokenExpiresIn:kNewIDTokenExpiresIn]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Completion is called."]; + +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + UIViewController *presentingViewController = [[UIViewController alloc] init]; + [previousUser addScopes:@[kNewScope] + presentingViewController:presentingViewController + completion:^(GIDUserAuth *userAuth, NSError *error) { + [expectation fulfill]; + XCTAssertNil(userAuth); + XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + }]; +#elif TARGET_OS_OSX + NSWindow *presentingWindow = [[NSWindow alloc] init]; + [previousUser addScopes:@[kNewScope] + presentingWindow:presentingWindow + completion:^(GIDUserAuth *userAuth, NSError *error) { + [expectation fulfill]; + XCTAssertNil(userAuth); + XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + }]; +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + #pragma mark - Helpers // Returns a GIDGoogleUser with different tokens expiresIn time. The token strings are constants. diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 65b2ae51..93c29a6f 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -83,14 +83,16 @@ final class GoogleSignInAuthenticator: ObservableObject { /// - note: Successful requests will update the `authViewModel.state` with a new current user that /// has the granted scope. func addBirthdayReadScope(completion: @escaping () -> Void) { - let currentUser = GIDSignIn.sharedInstance.currentUser + guard let currentUser = GIDSignIn.sharedInstance.currentUser else { + fatalError("No user signed in!") + } #if os(iOS) guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { fatalError("No root view controller!") } - currentUser?.addScopes([BirthdayLoader.birthdayReadScope], + currentUser.addScopes([BirthdayLoader.birthdayReadScope], presenting: rootViewController) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") @@ -107,8 +109,8 @@ final class GoogleSignInAuthenticator: ObservableObject { fatalError("No presenting window!") } - currentUser?.addScopes([BirthdayLoader.birthdayReadScope], - presenting: presentingWindow) { userAuth, error in + currentUser.addScopes([BirthdayLoader.birthdayReadScope], + presenting: presentingWindow) { userAuth, error in if let error = error { print("Found error while adding birthday read scope: \(error).") return From 042912cf696db860e6ffd9ff0777c18952ea2160 Mon Sep 17 00:00:00 2001 From: pinlu Date: Tue, 25 Oct 2022 17:57:00 -0700 Subject: [PATCH 09/13] Resolve comments. --- GoogleSignIn/Sources/GIDSignIn.m | 28 --------- GoogleSignIn/Sources/GIDSignIn_Private.h | 4 +- .../Sources/Public/GoogleSignIn/GIDSignIn.h | 8 +-- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 58 +++++++++++++++---- .../Source/SignInViewController.m | 4 +- 5 files changed, 54 insertions(+), 48 deletions(-) diff --git a/GoogleSignIn/Sources/GIDSignIn.m b/GoogleSignIn/Sources/GIDSignIn.m index cde8e205..56490155 100644 --- a/GoogleSignIn/Sources/GIDSignIn.m +++ b/GoogleSignIn/Sources/GIDSignIn.m @@ -265,20 +265,6 @@ - (void)signInWithPresentingViewController:(UIViewController *)presentingViewCon - (void)addScopes:(NSArray *)scopes presentingViewController:(UIViewController *)presentingViewController completion:(nullable GIDUserAuthCompletion)completion { - // A currentUser must be available in order to complete this flow. - if (!self.currentUser) { - // No currentUser is set, notify callback of failure. - NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeNoCurrentUser - userInfo:nil]; - if (completion) { - dispatch_async(dispatch_get_main_queue(), ^{ - completion(nil, error); - }); - } - return; - } - GIDConfiguration *configuration = self.currentUser.configuration; GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration @@ -350,20 +336,6 @@ - (void)signInWithPresentingWindow:(NSWindow *)presentingWindow - (void)addScopes:(NSArray *)scopes presentingWindow:(NSWindow *)presentingWindow completion:(nullable GIDUserAuthCompletion)completion { - // A currentUser must be available in order to complete this flow. - if (!self.currentUser) { - // No currentUser is set, notify callback of failure. - NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeNoCurrentUser - userInfo:nil]; - if (completion) { - dispatch_async(dispatch_get_main_queue(), ^{ - completion(nil, error); - }); - } - return; - } - GIDConfiguration *configuration = self.currentUser.configuration; GIDSignInInternalOptions *options = [GIDSignInInternalOptions defaultOptionsWithConfiguration:configuration diff --git a/GoogleSignIn/Sources/GIDSignIn_Private.h b/GoogleSignIn/Sources/GIDSignIn_Private.h index 76907568..39df848f 100644 --- a/GoogleSignIn/Sources/GIDSignIn_Private.h +++ b/GoogleSignIn/Sources/GIDSignIn_Private.h @@ -55,7 +55,7 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * #if TARGET_OS_IOS || TARGET_OS_MACCATALYST -/// Starts an interactive consent flow on iOS to add scopes to the user's grants. +/// Starts an interactive consent flow on iOS to add scopes to the current user's grants. /// /// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. @@ -74,7 +74,7 @@ typedef void (^GIDUserAuthCompletion)(GIDUserAuth *_Nullable userAuth, NSError * #elif TARGET_OS_OSX -/// Starts an interactive consent flow on macOS to add scopes to the user's grants +/// Starts an interactive consent flow on macOS to add scopes to the current user's grants. /// /// The completion will be called at the end of this process. If successful, a `GIDUserAuth` /// instance will be returned reflecting the new scopes and saved sign-in state will be updated. diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index 2d020fc0..bba85a25 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -45,12 +45,10 @@ typedef NS_ERROR_ENUM(kGIDSignInErrorDomain, GIDSignInErrorCode) { kGIDSignInErrorCodeCanceled = -5, /// Indicates an Enterprise Mobility Management related error has occurred. kGIDSignInErrorCodeEMM = -6, - /// Indicates there is no `currentUser`. - kGIDSignInErrorCodeNoCurrentUser = -7, - /// Indicates there is an operation on a previous user. - kGIDSignInErrorCodePreviousUser = -8, /// Indicates the requested scopes have already been granted to the `currentUser`. - kGIDSignInErrorCodeScopesAlreadyGranted = -9, + kGIDSignInErrorCodeScopesAlreadyGranted = -8, + /// Indicates there is an operation on a previous user. + kGIDSignInErrorCodePreviousUser = -9, }; /// Represents a completion block that takes an error if the operation was unsuccessful. diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 460350dd..6b4cad89 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -448,11 +448,11 @@ - (void)testAddScopes_success { OCMStub([signIn sharedInstance]).andReturn(signIn); [[signIn expect] addScopes:OCMOCK_ANY #if TARGET_OS_IOS || TARGET_OS_MACCATALYST - presentingViewController:OCMOCK_ANY + presentingViewController:OCMOCK_ANY #elif TARGET_OS_OSX - presentingWindow:OCMOCK_ANY + presentingWindow:OCMOCK_ANY #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST - completion:OCMOCK_ANY]; + completion:OCMOCK_ANY]; GIDGoogleUser *currentUser = [self googleUserWithAccessTokenExpiresIn:kAccessTokenExpiresIn idTokenExpiresIn:kIDTokenExpiresIn]; @@ -462,19 +462,19 @@ - (void)testAddScopes_success { #if TARGET_OS_IOS || TARGET_OS_MACCATALYST UIViewController *presentingViewController = [[UIViewController alloc] init]; [currentUser addScopes:@[kNewScope] - presentingViewController:presentingViewController - completion:nil]; + presentingViewController:presentingViewController + completion:nil]; #elif TARGET_OS_OSX NSWindow *presentingWindow = [[NSWindow alloc] init]; [currentUser addScopes:@[kNewScope] - presentingWindow:presentingWindow - completion:nil]; + presentingWindow:presentingWindow + completion:nil]; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST [signIn verify]; } -- (void)testAddScopes_failure_addScopesToPreviousAccount { +- (void)testAddScopes_failure_addScopesToPreviousUser { id signIn = OCMClassMock([GIDSignIn class]); OCMStub([signIn sharedInstance]).andReturn(signIn); @@ -492,8 +492,8 @@ - (void)testAddScopes_failure_addScopesToPreviousAccount { #if TARGET_OS_IOS || TARGET_OS_MACCATALYST UIViewController *presentingViewController = [[UIViewController alloc] init]; [previousUser addScopes:@[kNewScope] - presentingViewController:presentingViewController - completion:^(GIDUserAuth *userAuth, NSError *error) { + presentingViewController:presentingViewController + completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); @@ -502,7 +502,43 @@ - (void)testAddScopes_failure_addScopesToPreviousAccount { NSWindow *presentingWindow = [[NSWindow alloc] init]; [previousUser addScopes:@[kNewScope] presentingWindow:presentingWindow - completion:^(GIDUserAuth *userAuth, NSError *error) { + completion:^(GIDUserAuth *userAuth, NSError *error) { + [expectation fulfill]; + XCTAssertNil(userAuth); + XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + }]; +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testAddScopes_failure_addScopesToPreviousUser_currentUserIsNull { + id signIn = OCMClassMock([GIDSignIn class]); + OCMStub([signIn sharedInstance]).andReturn(signIn); + + GIDGoogleUser *currentUser = nil; + OCMStub([signIn currentUser]).andReturn(currentUser); + + GIDGoogleUser *previousUser = [self googleUserWithAccessTokenExpiresIn:kAccessTokenExpiresIn + idTokenExpiresIn:kNewIDTokenExpiresIn]; + + XCTestExpectation *expectation = + [self expectationWithDescription:@"Completion is called."]; + +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + UIViewController *presentingViewController = [[UIViewController alloc] init]; + [previousUser addScopes:@[kNewScope] + presentingViewController:presentingViewController + completion:^(GIDUserAuth *userAuth, NSError *error) { + [expectation fulfill]; + XCTAssertNil(userAuth); + XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + }]; +#elif TARGET_OS_OSX + NSWindow *presentingWindow = [[NSWindow alloc] init]; + [previousUser addScopes:@[kNewScope] + presentingWindow:presentingWindow + completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); diff --git a/Samples/ObjC/SignInSample/Source/SignInViewController.m b/Samples/ObjC/SignInSample/Source/SignInViewController.m index 038f754a..8524bb26 100644 --- a/Samples/ObjC/SignInSample/Source/SignInViewController.m +++ b/Samples/ObjC/SignInSample/Source/SignInViewController.m @@ -282,8 +282,8 @@ - (IBAction)disconnect:(id)sender { - (IBAction)addScopes:(id)sender { GIDGoogleUser *currentUser = GIDSignIn.sharedInstance.currentUser; [currentUser addScopes:@[ @"https://www.googleapis.com/auth/user.birthday.read" ] - presentingViewController:self - completion:^(GIDUserAuth *_Nullable userAuth, + presentingViewController:self + completion:^(GIDUserAuth *_Nullable userAuth, NSError *_Nullable error) { if (error) { self->_signInAuthStatus.text = [NSString stringWithFormat:@"Status: Failed to add scopes: %@", From a9953ef46b8d133ec45bfda8dc9acb5e73e2c072 Mon Sep 17 00:00:00 2001 From: pinlu Date: Wed, 26 Oct 2022 15:09:26 -0700 Subject: [PATCH 10/13] Rename new error code as "kGIDSignInErrorCodeMismatchWithCurrentUser" --- GoogleSignIn/Sources/GIDGoogleUser.m | 2 +- GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h | 2 +- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index fa028a03..bff7ca8f 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -197,7 +197,7 @@ - (void)addScopes:(NSArray *)scopes if (self != GIDSignIn.sharedInstance.currentUser) { NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodePreviousUser + code:kGIDSignInErrorCodeMismatchWithCurrentUser userInfo:nil]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h index bba85a25..5abf4f6f 100644 --- a/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h +++ b/GoogleSignIn/Sources/Public/GoogleSignIn/GIDSignIn.h @@ -48,7 +48,7 @@ typedef NS_ERROR_ENUM(kGIDSignInErrorDomain, GIDSignInErrorCode) { /// Indicates the requested scopes have already been granted to the `currentUser`. kGIDSignInErrorCodeScopesAlreadyGranted = -8, /// Indicates there is an operation on a previous user. - kGIDSignInErrorCodePreviousUser = -9, + kGIDSignInErrorCodeMismatchWithCurrentUser = -9, }; /// Represents a completion block that takes an error if the operation was unsuccessful. diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 6b4cad89..a512caf0 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -496,7 +496,7 @@ - (void)testAddScopes_failure_addScopesToPreviousUser { completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; #elif TARGET_OS_OSX NSWindow *presentingWindow = [[NSWindow alloc] init]; @@ -505,7 +505,7 @@ - (void)testAddScopes_failure_addScopesToPreviousUser { completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST @@ -532,7 +532,7 @@ - (void)testAddScopes_failure_addScopesToPreviousUser_currentUserIsNull { completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; #elif TARGET_OS_OSX NSWindow *presentingWindow = [[NSWindow alloc] init]; @@ -541,7 +541,7 @@ - (void)testAddScopes_failure_addScopesToPreviousUser_currentUserIsNull { completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodePreviousUser); + XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST From f664388a9a4ecb0a3f12fa93679bb4b205378c5a Mon Sep 17 00:00:00 2001 From: pinlu Date: Thu, 27 Oct 2022 10:57:14 -0700 Subject: [PATCH 11/13] Resolve comments --- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 36 ++++++--------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index a512caf0..6e48479e 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -489,25 +489,17 @@ - (void)testAddScopes_failure_addScopesToPreviousUser { XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called."]; -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST - UIViewController *presentingViewController = [[UIViewController alloc] init]; [previousUser addScopes:@[kNewScope] - presentingViewController:presentingViewController - completion:^(GIDUserAuth *userAuth, NSError *error) { - [expectation fulfill]; - XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); - }]; +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + presentingViewController:[[UIViewController alloc] init] #elif TARGET_OS_OSX - NSWindow *presentingWindow = [[NSWindow alloc] init]; - [previousUser addScopes:@[kNewScope] - presentingWindow:presentingWindow - completion:^(GIDUserAuth *userAuth, NSError *error) { + presentingWindow:[[NSWindow alloc] init] +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; -#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -525,25 +517,17 @@ - (void)testAddScopes_failure_addScopesToPreviousUser_currentUserIsNull { XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called."]; -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST - UIViewController *presentingViewController = [[UIViewController alloc] init]; [previousUser addScopes:@[kNewScope] - presentingViewController:presentingViewController - completion:^(GIDUserAuth *userAuth, NSError *error) { - [expectation fulfill]; - XCTAssertNil(userAuth); - XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); - }]; +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + presentingViewController:[[UIViewController alloc] init] #elif TARGET_OS_OSX - NSWindow *presentingWindow = [[NSWindow alloc] init]; - [previousUser addScopes:@[kNewScope] - presentingWindow:presentingWindow - completion:^(GIDUserAuth *userAuth, NSError *error) { + presentingWindow:[[NSWindow alloc] init] +#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + completion:^(GIDUserAuth *userAuth, NSError *error) { [expectation fulfill]; XCTAssertNil(userAuth); XCTAssertEqual(error.code, kGIDSignInErrorCodeMismatchWithCurrentUser); }]; -#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST [self waitForExpectationsWithTimeout:1 handler:nil]; } From cffd65eab038e5f35dd046bf2db1ed737bec1338 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 28 Oct 2022 12:30:58 -0700 Subject: [PATCH 12/13] Resolved comments --- GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m index 6e48479e..5261872a 100644 --- a/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m +++ b/GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m @@ -459,17 +459,13 @@ - (void)testAddScopes_success { OCMStub([signIn currentUser]).andReturn(currentUser); -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST - UIViewController *presentingViewController = [[UIViewController alloc] init]; [currentUser addScopes:@[kNewScope] - presentingViewController:presentingViewController - completion:nil]; +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST + presentingViewController:[[UIViewController alloc] init] #elif TARGET_OS_OSX - NSWindow *presentingWindow = [[NSWindow alloc] init]; - [currentUser addScopes:@[kNewScope] - presentingWindow:presentingWindow - completion:nil]; + presentingWindow:[[NSWindow alloc] init] #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST + completion:nil]; [signIn verify]; } From 64b8564770bca408687c427d4a61e4e1023d0308 Mon Sep 17 00:00:00 2001 From: pinlu Date: Fri, 28 Oct 2022 13:40:02 -0700 Subject: [PATCH 13/13] Resolve comment --- GoogleSignIn/Sources/GIDGoogleUser.m | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/GoogleSignIn/Sources/GIDGoogleUser.m b/GoogleSignIn/Sources/GIDGoogleUser.m index bff7ca8f..ca35edfa 100644 --- a/GoogleSignIn/Sources/GIDGoogleUser.m +++ b/GoogleSignIn/Sources/GIDGoogleUser.m @@ -183,18 +183,14 @@ - (OIDAuthState *) authState{ return ((GTMAppAuthFetcherAuthorization *)self.fetcherAuthorizer).authState; } -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST - (void)addScopes:(NSArray *)scopes +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST presentingViewController:(UIViewController *)presentingViewController - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion { #elif TARGET_OS_OSX || TARGET_OS_MACCATALYST -- (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, - NSError *_Nullable error))completion { + presentingWindow:(NSWindow *)presentingWindow #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST - + completion:(nullable void (^)(GIDUserAuth *_Nullable userAuth, + NSError *_Nullable error))completion { if (self != GIDSignIn.sharedInstance.currentUser) { NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain code:kGIDSignInErrorCodeMismatchWithCurrentUser @@ -207,15 +203,13 @@ - (void)addScopes:(NSArray *)scopes return; } -#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST [GIDSignIn.sharedInstance addScopes:scopes +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST presentingViewController:presentingViewController - completion:completion]; #elif TARGET_OS_OSX || TARGET_OS_MACCATALYST - [GIDSignIn.sharedInstance addScopes:scopes presentingWindow:presentingWindow - completion:completion]; #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST + completion:completion]; } #pragma mark - Private Methods