Kaynağa Gözat

Make tokens in GIDGoogleUser KVO-compliant (#222)

pinlu 3 yıl önce
ebeveyn
işleme
405dc51beb

+ 40 - 43
GoogleSignIn/Sources/GIDGoogleUser.m

@@ -42,12 +42,19 @@ static NSString *const kOpenIDRealmParameter = @"openid.realm";
 
 NS_ASSUME_NONNULL_BEGIN
 
+@interface GIDGoogleUser ()
+
+@property(nonatomic, readwrite) GIDToken *accessToken;
+
+@property(nonatomic, readwrite) GIDToken *refreshToken;
+
+@property(nonatomic, readwrite, nullable) GIDToken *idToken;
+
+@end
+
 @implementation GIDGoogleUser {
   OIDAuthState *_authState;
   GIDConfiguration *_cachedConfiguration;
-  GIDToken *_cachedAccessToken;
-  GIDToken *_cachedRefreshToken;
-  GIDToken *_cachedIdToken;
 }
 
 - (nullable NSString *)userID {
@@ -59,7 +66,6 @@ NS_ASSUME_NONNULL_BEGIN
       return [idTokenDecoded.subject copy];
     }
   }
-
   return nil;
 }
 
@@ -97,44 +103,9 @@ NS_ASSUME_NONNULL_BEGIN
                                                             openIDRealm:openIDRealm];
     };
   }
-  
   return _cachedConfiguration;
 }
 
-- (GIDToken *)accessToken {
-  @synchronized(self) {
-    if (!_cachedAccessToken) {
-      _cachedAccessToken = [[GIDToken alloc] initWithTokenString:_authState.lastTokenResponse.accessToken
-                                                  expirationDate:_authState.lastTokenResponse.
-                                                                     accessTokenExpirationDate];
-    }
-  }
-  return _cachedAccessToken;
-}
-
-- (GIDToken *)refreshToken {
-  @synchronized(self) {
-    if (!_cachedRefreshToken) {
-      _cachedRefreshToken = [[GIDToken alloc] initWithTokenString:_authState.refreshToken
-                                                   expirationDate:nil];
-    }
-  }
-  return _cachedRefreshToken;
-}
-
-- (nullable GIDToken *)idToken {
-  @synchronized(self) {
-    NSString *idTokenString = _authState.lastTokenResponse.idToken;
-    if (!_cachedIdToken && idTokenString) {
-      NSDate *idTokenExpirationDate = [[[OIDIDToken alloc]
-                                        initWithIDTokenString:idTokenString] expiresAt];
-      _cachedIdToken = [[GIDToken alloc] initWithTokenString:idTokenString
-                                              expirationDate:idTokenExpirationDate];
-    }
-  }
-  return _cachedIdToken;
-}
-
 #pragma mark - Private Methods
 
 - (instancetype)initWithAuthState:(OIDAuthState *)authState
@@ -153,10 +124,36 @@ NS_ASSUME_NONNULL_BEGIN
     _authentication = [[GIDAuthentication alloc] initWithAuthState:authState];
     _profile = profileData;
     
-    // These three tokens will be generated in the getter and cached .
-    _cachedAccessToken = nil;
-    _cachedRefreshToken = nil;
-    _cachedIdToken = nil;
+    [self updateTokensWithAuthState:authState];
+  }
+}
+
+- (void)updateTokensWithAuthState:(OIDAuthState *)authState {
+  GIDToken *accessToken =
+      [[GIDToken alloc] initWithTokenString:authState.lastTokenResponse.accessToken
+                             expirationDate:authState.lastTokenResponse.accessTokenExpirationDate];
+  if (![self.accessToken isEqualToToken:accessToken]) {
+    self.accessToken = accessToken;
+  }
+  
+  GIDToken *refreshToken = [[GIDToken alloc] initWithTokenString:authState.refreshToken
+                                                  expirationDate:nil];
+  if (![self.refreshToken isEqualToToken:refreshToken]) {
+    self.refreshToken = refreshToken;
+  }
+  
+  GIDToken *idToken;
+  NSString *idTokenString = authState.lastTokenResponse.idToken;
+  if (idTokenString) {
+    NSDate *idTokenExpirationDate =
+        [[[OIDIDToken alloc] initWithIDTokenString:idTokenString] expiresAt];
+    idToken = [[GIDToken alloc] initWithTokenString:idTokenString
+                                     expirationDate:idTokenExpirationDate];
+  } else {
+    idToken = nil;
+  }
+  if ((self.idToken || idToken) && ![self.idToken isEqualToToken:idToken]) {
+    self.idToken = idToken;
   }
 }
 

+ 2 - 0
GoogleSignIn/Tests/Unit/GIDAuthenticationTest.m

@@ -561,6 +561,7 @@ _Static_assert(kChangeTypeEnd == (sizeof(kObservedProperties) / sizeof(*kObserve
       [OIDTokenResponse testInstanceWithIDToken:idToken
                                     accessToken:kAccessToken
                                       expiresIn:accessTokenExpiresIn
+                                   refreshToken:kRefreshToken
                                    tokenRequest:tokenRequest];
   return [[GIDAuthentication alloc]
       initWithAuthState:[OIDAuthState testInstanceWithTokenResponse:tokenResponse]];
@@ -599,6 +600,7 @@ _Static_assert(kChangeTypeEnd == (sizeof(kObservedProperties) / sizeof(*kObserve
   return [OIDTokenResponse testInstanceWithIDToken:(_hasIDToken ? [self idTokenNew] : nil)
                                        accessToken:kNewAccessToken
                                          expiresIn:expiresIn
+                                      refreshToken:kRefreshToken
                                       tokenRequest:_tokenRequest ?: nil];
 }
 

+ 43 - 7
GoogleSignIn/Tests/Unit/GIDGoogleUserTest.m

@@ -36,6 +36,8 @@
 #endif
 
 static NSString *const kNewAccessToken = @"new_access_token";
+static NSString *const kNewRefreshToken = @"new_refresh_token";
+
 static NSTimeInterval const kTimeAccuracy = 10;
 // The difference between times.
 // It should be larger than kTimeAccuracy which is used in the method `XCTAssertEqualWithAccuracy`.
@@ -102,19 +104,16 @@ static NSTimeInterval const kTimeIncrement = 100;
   NSTimeInterval accessTokenExpireTime = [[NSDate date] timeIntervalSince1970];
   NSTimeInterval idTokenExpireTime = accessTokenExpireTime + kTimeIncrement;
   
-  NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
-  OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
-                                                      accessToken:kAccessToken
-                                            accessTokenExpireTime:accessTokenExpireTime];
-  
-  GIDGoogleUser *user = [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
+  GIDGoogleUser *user = [self googleUserWithAccessTokenExpireTime:accessTokenExpireTime
+                                                idTokenExpireTime:idTokenExpireTime];
   
   NSTimeInterval updatedAccessTokenExpireTime = idTokenExpireTime + kTimeIncrement;
   NSTimeInterval updatedIDTokenExpireTime = updatedAccessTokenExpireTime + kTimeIncrement;
   NSString *updatedIDToken = [self idTokenWithExpireTime:updatedIDTokenExpireTime];
   OIDAuthState *updatedAuthState = [OIDAuthState testInstanceWithIDToken:updatedIDToken
                                                              accessToken:kNewAccessToken
-                                                   accessTokenExpireTime:updatedAccessTokenExpireTime];
+                                                   accessTokenExpireTime:updatedAccessTokenExpireTime
+                                                            refreshToken:kNewRefreshToken];
   GIDProfileData *updatedProfileData = [GIDProfileData testInstance];
   
   [user updateAuthState:updatedAuthState profileData:updatedProfileData];
@@ -125,11 +124,48 @@ static NSTimeInterval const kTimeIncrement = 100;
   XCTAssertEqualObjects(user.idToken.tokenString, updatedIDToken);
   XCTAssertEqualWithAccuracy([user.idToken.expirationDate timeIntervalSince1970],
                              updatedIDTokenExpireTime, kTimeAccuracy);
+  XCTAssertEqualObjects(user.refreshToken.tokenString, kNewRefreshToken);
   XCTAssertEqual(user.profile, updatedProfileData);
 }
 
+// When updating with a new OIDAuthState in which token information is not changed, the token objects
+// should remain the same.
+- (void)testUpdateAuthState_tokensAreNotChanged {
+  NSTimeInterval accessTokenExpireTime = [[NSDate date] timeIntervalSince1970];
+  NSTimeInterval idTokenExpireTime = [[NSDate date] timeIntervalSince1970];
+  
+  NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
+  OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
+                                                      accessToken:kAccessToken
+                                            accessTokenExpireTime:accessTokenExpireTime
+                                                     refreshToken:kRefreshToken];
+  
+  GIDGoogleUser *user = [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
+  
+  GIDToken *accessTokenBeforeUpdate = user.accessToken;
+  GIDToken *refreshTokenBeforeUpdate = user.refreshToken;
+  GIDToken *idTokenBeforeUpdate = user.idToken;
+  
+  [user updateAuthState:authState profileData:nil];
+  
+  XCTAssertIdentical(user.accessToken, accessTokenBeforeUpdate);
+  XCTAssertIdentical(user.idToken, idTokenBeforeUpdate);
+  XCTAssertIdentical(user.refreshToken, refreshTokenBeforeUpdate);
+}
+
 #pragma mark - Helpers
 
+- (GIDGoogleUser *)googleUserWithAccessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
+                                     idTokenExpireTime:(NSTimeInterval)idTokenExpireTime {
+  NSString *idToken = [self idTokenWithExpireTime:idTokenExpireTime];
+  OIDAuthState *authState = [OIDAuthState testInstanceWithIDToken:idToken
+                                                      accessToken:kAccessToken
+                                            accessTokenExpireTime:accessTokenExpireTime
+                                                     refreshToken:kRefreshToken];
+  
+  return [[GIDGoogleUser alloc] initWithAuthState:authState profileData:nil];
+}
+
 // The expireTime should be based on 1970.
 - (NSString *)idTokenWithExpireTime:(NSTimeInterval)expireTime {
   return [OIDTokenResponse idTokenWithSub:kUserID exp:@(expireTime)];

+ 1 - 0
GoogleSignIn/Tests/Unit/GIDSignInTest.m

@@ -1202,6 +1202,7 @@ static void *kTestObserverContext = &kTestObserverContext;
       [OIDTokenResponse testInstanceWithIDToken:[OIDTokenResponse fatIDToken]
                                     accessToken:restoredSignIn ? kAccessToken : nil
                                       expiresIn:oldAccessToken ? @(300) : nil
+                                   refreshToken:kRefreshToken
                                    tokenRequest:nil];
 
   OIDTokenRequest *tokenRequest = [[OIDTokenRequest alloc]

+ 2 - 1
GoogleSignIn/Tests/Unit/OIDAuthState+Testing.h

@@ -30,6 +30,7 @@
 
 + (instancetype)testInstanceWithIDToken:(NSString *)idToken
                             accessToken:(NSString *)accessToken
-                  accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime;
+                  accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
+                           refreshToken:(NSString *)refreshToken;
 
 @end

+ 3 - 1
GoogleSignIn/Tests/Unit/OIDAuthState+Testing.m

@@ -35,13 +35,15 @@
 
 + (instancetype)testInstanceWithIDToken:(NSString *)idToken
                             accessToken:(NSString *)accessToken
-                  accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime {
+                  accessTokenExpireTime:(NSTimeInterval)accessTokenExpireTime
+                           refreshToken:(NSString *)refreshToken {
   NSNumber *accessTokenExpiresIn =
       @(accessTokenExpireTime - [[NSDate date] timeIntervalSince1970]);
   OIDTokenResponse *newResponse =
       [OIDTokenResponse testInstanceWithIDToken:idToken
                                     accessToken:accessToken
                                       expiresIn:accessTokenExpiresIn
+                                   refreshToken:refreshToken
                                    tokenRequest:nil];
   return [self testInstanceWithTokenResponse:newResponse];
 }

+ 1 - 0
GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.h

@@ -56,6 +56,7 @@ extern NSString * const kFatPictureURL;
 + (instancetype)testInstanceWithIDToken:(NSString *)idToken
                             accessToken:(NSString *)accessToken
                               expiresIn:(NSNumber *)expiresIn
+                           refreshToken:(NSString *)refreshToken
                            tokenRequest:(OIDTokenRequest *)tokenRequest;
 
 + (NSString *)idToken;

+ 3 - 1
GoogleSignIn/Tests/Unit/OIDTokenResponse+Testing.m

@@ -61,19 +61,21 @@ NSString * const kFatPictureURL = @"fake_user_picture_url";
   return [OIDTokenResponse testInstanceWithIDToken:idToken
                                        accessToken:nil
                                          expiresIn:nil
+                                      refreshToken:nil
                                       tokenRequest:nil];
 }
 
 + (instancetype)testInstanceWithIDToken:(NSString *)idToken
                             accessToken:(NSString *)accessToken
                               expiresIn:(NSNumber *)expiresIn
+                           refreshToken:(NSString *)refreshToken
                            tokenRequest:(OIDTokenRequest *)tokenRequest {
   NSMutableDictionary<NSString *, NSString *> *parameters;
   parameters = [[NSMutableDictionary alloc] initWithDictionary:@{
     @"access_token" : accessToken ?: kAccessToken,
     @"expires_in" : expiresIn ?: @(kAccessTokenExpiresIn),
     @"token_type" : @"example_token_type",
-    @"refresh_token" : kRefreshToken,
+    @"refresh_token" : refreshToken ?: kRefreshToken,
     @"scope" : [OIDScopeUtilities scopesWithArray:@[ OIDAuthorizationRequestTestingScope2 ]],
     @"server_code" : kServerAuthCode,
   }];