Explorar o código

Add GIDProfileDataFetcher protocol and implementation

The next step is to add a fake.
Before this we need to extract a new class GIDDataFetcher to encapsulate GTMAppAuthFetcherAuthorization and  GTMSessionFetcher.
pinlu %!s(int64=3) %!d(string=hai) anos
pai
achega
2db2d0cd38

+ 36 - 0
GoogleSignIn/Sources/GIDProfileDataFetcher/API/GIDProfileDataFetcher.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 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 <Foundation/Foundation.h>
+
+@class GIDProfileData;
+@class OIDAuthState;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol GIDProfileDataFetcher <NSObject>
+
+/// Fetches the latest @GIDProfileData object.
+///
+/// @param authState The state of the OAuth session.
+/// @param completion The block that is called on completion asynchronously.
+- (void)fetchProfileDataWithAuthState:(OIDAuthState *)authState
+                           completion:(void (^)(GIDProfileData *_Nullable profileData,
+                                                NSError *_Nullable error))completion;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 26 - 0
GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/GIDProfileDataFetcher.h

@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 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 <Foundation/Foundation.h>
+
+#import "GoogleSignIn/Sources/GIDProfileDataFetcher/API/GIDProfileDataFetcher.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GIDProfileDataFetcher : NSObject<GIDProfileDataFetcher>
+@end
+
+NS_ASSUME_NONNULL_END

+ 116 - 0
GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/GIDProfileDataFetcher.m

@@ -0,0 +1,116 @@
+#import "GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/GIDProfileDataFetcher.h"
+
+#import "GoogleSignIn/Sources/GIDSignInPreferences.h"
+
+#import "GoogleSignIn/Sources/GIDProfileData_Private.h"
+
+#ifdef SWIFT_PACKAGE
+@import AppAuth;
+@import GTMAppAuth;
+#else
+#import <AppAuth/AppAuth.h>
+#import <GTMAppAuth/GTMAppAuth.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+// The URL template for the URL to get user info.
+static NSString *const kUserInfoURLTemplate = @"https://%@/oauth2/v3/userinfo?access_token=%@";
+
+// Maximum retry interval in seconds for the fetcher.
+static const NSTimeInterval kFetcherMaxRetryInterval = 15.0;
+
+// Basic profile (Fat ID Token / userinfo endpoint) keys
+static NSString *const kBasicProfileEmailKey = @"email";
+static NSString *const kBasicProfilePictureKey = @"picture";
+static NSString *const kBasicProfileNameKey = @"name";
+static NSString *const kBasicProfileGivenNameKey = @"given_name";
+static NSString *const kBasicProfileFamilyNameKey = @"family_name";
+
+@implementation GIDProfileDataFetcher
+
+- (void)fetchProfileDataWithAuthState:(OIDAuthState *)authState
+                           completion:(void (^)(GIDProfileData *_Nullable profileData,
+                                                NSError *_Nullable error))completion {
+  OIDIDToken *idToken =
+      [[OIDIDToken alloc] initWithIDTokenString: authState.lastTokenResponse.idToken];
+  // If the profile data are present in the ID token, use them.
+  if (idToken) {
+    GIDProfileData *profileData = [self profileDataWithIDToken:idToken];
+    completion(profileData, nil);
+    return;
+  }
+  // If we can't retrieve profile data from the ID token, make a userInfo request to fetch them.
+  NSURL *infoURL = [NSURL URLWithString:
+      [NSString stringWithFormat:kUserInfoURLTemplate,
+          [GIDSignInPreferences googleUserInfoServer],
+          authState.lastTokenResponse.accessToken]];
+  [self startFetchURL:infoURL
+              fromAuthState:authState
+                withComment:@"GIDSignIn: fetch basic profile info"
+      withCompletionHandler:^(NSData *data, NSError *error) {
+    if (error) {
+      completion(nil, error);
+    } else {
+      NSError *jsonDeserializationError;
+      NSDictionary<NSString *, NSString *> *profileDict =
+        [NSJSONSerialization JSONObjectWithData:data
+                                        options:NSJSONReadingMutableContainers
+                                          error:&jsonDeserializationError];
+      if (profileDict) {
+        GIDProfileData *profileData = [[GIDProfileData alloc]
+            initWithEmail:idToken.claims[kBasicProfileEmailKey]
+                     name:profileDict[kBasicProfileNameKey]
+                givenName:profileDict[kBasicProfileGivenNameKey]
+               familyName:profileDict[kBasicProfileFamilyNameKey]
+                 imageURL:[NSURL URLWithString:profileDict[kBasicProfilePictureKey]]];
+        completion(profileData, nil);
+      }
+      else {
+        completion(nil, error);
+      }
+    }
+  }];
+}
+
+// Generates user profile from OIDIDToken.
+- (GIDProfileData *)profileDataWithIDToken:(OIDIDToken *)idToken {
+  if (!idToken ||
+      !idToken.claims[kBasicProfilePictureKey] ||
+      !idToken.claims[kBasicProfileNameKey] ||
+      !idToken.claims[kBasicProfileGivenNameKey] ||
+      !idToken.claims[kBasicProfileFamilyNameKey]) {
+    return nil;
+  }
+
+  return [[GIDProfileData alloc]
+      initWithEmail:idToken.claims[kBasicProfileEmailKey]
+               name:idToken.claims[kBasicProfileNameKey]
+          givenName:idToken.claims[kBasicProfileGivenNameKey]
+          familyName:idToken.claims[kBasicProfileFamilyNameKey]
+            imageURL:[NSURL URLWithString:idToken.claims[kBasicProfilePictureKey]]];
+}
+   
+- (void)startFetchURL:(NSURL *)URL
+            fromAuthState:(OIDAuthState *)authState
+              withComment:(NSString *)comment
+    withCompletionHandler:(void (^)(NSData *, NSError *))handler {
+  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
+  GTMSessionFetcher *fetcher;
+  GTMAppAuthFetcherAuthorization *authorization =
+      [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];
+  id<GTMSessionFetcherServiceProtocol> fetcherService = authorization.fetcherService;
+  if (fetcherService) {
+    fetcher = [fetcherService fetcherWithRequest:request];
+  } else {
+    fetcher = [GTMSessionFetcher fetcherWithRequest:request];
+  }
+  fetcher.retryEnabled = YES;
+  fetcher.maxRetryInterval = kFetcherMaxRetryInterval;
+  fetcher.comment = comment;
+  [fetcher beginFetchWithCompletionHandler:handler];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 61 - 39
GoogleSignIn/Sources/GIDSignIn.m

@@ -24,6 +24,8 @@
 #import "GoogleSignIn/Sources/GIDEMMSupport.h"
 #import "GoogleSignIn/Sources/GIDKeychainHandler/API/GIDKeychainHandler.h"
 #import "GoogleSignIn/Sources/GIDKeychainHandler/Implementations/GIDKeychainHandler.h"
+#import "GoogleSignIn/Sources/GIDProfileDataFetcher/API/GIDProfileDataFetcher.h"
+#import "GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/GIDProfileDataFetcher.h"
 #import "GoogleSignIn/Sources/GIDSignInInternalOptions.h"
 #import "GoogleSignIn/Sources/GIDSignInPreferences.h"
 #import "GoogleSignIn/Sources/GIDCallbackQueue.h"
@@ -170,6 +172,8 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
   BOOL _restarting;
   
   id<GIDKeychainHandler> _keychainHandler;
+  
+  id<GIDProfileDataFetcher> _profileDataFetcher;
 }
 
 #pragma mark - Public methods
@@ -491,6 +495,8 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
 #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
     
     _keychainHandler = keychainHandler;
+    
+    _profileDataFetcher = [[GIDProfileDataFetcher alloc] init];
   }
   return self;
 }
@@ -807,45 +813,61 @@ static NSString *const kConfigOpenIDRealmKey = @"GIDOpenIDRealm";
     if (!authState || handlerAuthFlow.error) {
       return;
     }
-    OIDIDToken *idToken =
-        [[OIDIDToken alloc] initWithIDTokenString: authState.lastTokenResponse.idToken];
-    // If the profile data are present in the ID token, use them.
-    if (idToken) {
-      handlerAuthFlow.profileData = [self profileDataWithIDToken:idToken];
-    }
-
-    // If we can't retrieve profile data from the ID token, make a userInfo request to fetch them.
-    if (!handlerAuthFlow.profileData) {
-      [handlerAuthFlow wait];
-      NSURL *infoURL = [NSURL URLWithString:
-          [NSString stringWithFormat:kUserInfoURLTemplate,
-              [GIDSignInPreferences googleUserInfoServer],
-              authState.lastTokenResponse.accessToken]];
-      [self startFetchURL:infoURL
-                  fromAuthState:authState
-                    withComment:@"GIDSignIn: fetch basic profile info"
-          withCompletionHandler:^(NSData *data, NSError *error) {
-        if (data && !error) {
-          NSError *jsonDeserializationError;
-          NSDictionary<NSString *, NSString *> *profileDict =
-              [NSJSONSerialization JSONObjectWithData:data
-                                              options:NSJSONReadingMutableContainers
-                                                error:&jsonDeserializationError];
-          if (profileDict) {
-            handlerAuthFlow.profileData = [[GIDProfileData alloc]
-                initWithEmail:idToken.claims[kBasicProfileEmailKey]
-                          name:profileDict[kBasicProfileNameKey]
-                    givenName:profileDict[kBasicProfileGivenNameKey]
-                    familyName:profileDict[kBasicProfileFamilyNameKey]
-                      imageURL:[NSURL URLWithString:profileDict[kBasicProfilePictureKey]]];
-          }
-        }
-        if (error) {
-          handlerAuthFlow.error = error;
-        }
-        [handlerAuthFlow next];
-      }];
-    }
+    
+    [handlerAuthFlow wait];
+    
+    [_profileDataFetcher
+        fetchProfileDataWithAuthState:(OIDAuthState *)authState
+                           completion:^(GIDProfileData *_Nullable profileData,
+                                        NSError *_Nullable error) {
+      if (error) {
+        handlerAuthFlow.error = error;
+      } else {
+        handlerAuthFlow.profileData = profileData;
+      }
+      [handlerAuthFlow next];
+    }];
+    
+    
+//    OIDIDToken *idToken =
+//        [[OIDIDToken alloc] initWithIDTokenString: authState.lastTokenResponse.idToken];
+//    // If the profile data are present in the ID token, use them.
+//    if (idToken) {
+//      handlerAuthFlow.profileData = [self profileDataWithIDToken:idToken];
+//    }
+//
+//    // If we can't retrieve profile data from the ID token, make a userInfo request to fetch them.
+//    if (!handlerAuthFlow.profileData) {
+//      [handlerAuthFlow wait];
+//      NSURL *infoURL = [NSURL URLWithString:
+//          [NSString stringWithFormat:kUserInfoURLTemplate,
+//              [GIDSignInPreferences googleUserInfoServer],
+//              authState.lastTokenResponse.accessToken]];
+//      [self startFetchURL:infoURL
+//                  fromAuthState:authState
+//                    withComment:@"GIDSignIn: fetch basic profile info"
+//          withCompletionHandler:^(NSData *data, NSError *error) {
+//        if (data && !error) {
+//          NSError *jsonDeserializationError;
+//          NSDictionary<NSString *, NSString *> *profileDict =
+//              [NSJSONSerialization JSONObjectWithData:data
+//                                              options:NSJSONReadingMutableContainers
+//                                                error:&jsonDeserializationError];
+//          if (profileDict) {
+//            handlerAuthFlow.profileData = [[GIDProfileData alloc]
+//                initWithEmail:idToken.claims[kBasicProfileEmailKey]
+//                          name:profileDict[kBasicProfileNameKey]
+//                    givenName:profileDict[kBasicProfileGivenNameKey]
+//                    familyName:profileDict[kBasicProfileFamilyNameKey]
+//                      imageURL:[NSURL URLWithString:profileDict[kBasicProfilePictureKey]]];
+//          }
+//        }
+//        if (error) {
+//          handlerAuthFlow.error = error;
+//        }
+//        [handlerAuthFlow next];
+//      }];
+//    }
   }];
 }