Bump External dependencies.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
NSMutableDictionary *requestIDMap_;
|
||||
BOOL skipAuthorization_;
|
||||
NSDictionary *additionalHTTPHeaders_;
|
||||
NSDictionary *urlQueryParameters_;
|
||||
}
|
||||
|
||||
// Queries included in this batch. Each query should have a unique requestID.
|
||||
@@ -42,6 +43,10 @@
|
||||
// additionalHTTPHeaders.
|
||||
@property (copy) NSDictionary *additionalHTTPHeaders;
|
||||
|
||||
// Any URL query parameters to add to the query (useful for debugging with some
|
||||
// services).
|
||||
@property (copy) NSDictionary *urlQueryParameters;
|
||||
|
||||
+ (id)batchQuery;
|
||||
+ (id)batchQueryWithQueries:(NSArray *)array;
|
||||
|
||||
|
@@ -22,7 +22,8 @@
|
||||
@implementation GTLBatchQuery
|
||||
|
||||
@synthesize shouldSkipAuthorization = skipAuthorization_,
|
||||
additionalHTTPHeaders = additionalHTTPHeaders_;
|
||||
additionalHTTPHeaders = additionalHTTPHeaders_,
|
||||
urlQueryParameters = urlQueryParameters_;
|
||||
|
||||
+ (id)batchQuery {
|
||||
GTLBatchQuery *obj = [[[self alloc] init] autorelease];
|
||||
@@ -49,6 +50,7 @@
|
||||
- (void)dealloc {
|
||||
[queries_ release];
|
||||
[additionalHTTPHeaders_ release];
|
||||
[urlQueryParameters_ release];
|
||||
[requestIDMap_ release];
|
||||
|
||||
[super dealloc];
|
||||
|
@@ -28,6 +28,7 @@
|
||||
- (BOOL)shouldSkipAuthorization;
|
||||
- (void)executionDidStop;
|
||||
- (NSDictionary *)additionalHTTPHeaders;
|
||||
- (NSDictionary *)urlQueryParameters;
|
||||
- (GTLUploadParameters *)uploadParameters;
|
||||
@end
|
||||
|
||||
@@ -78,7 +79,7 @@
|
||||
// or data must be provided.
|
||||
@property (copy) GTLUploadParameters *uploadParameters;
|
||||
|
||||
// Any url query parameters to add to the query (useful for debugging with some
|
||||
// Any URL query parameters to add to the query (useful for debugging with some
|
||||
// services).
|
||||
@property (copy) NSDictionary *urlQueryParameters;
|
||||
|
||||
|
@@ -755,7 +755,7 @@ static NSString *ETagIfPresent(GTLObject *obj) {
|
||||
|
||||
// Build up the array of RPC calls.
|
||||
NSMutableArray *rpcPayloads = [NSMutableArray arrayWithCapacity:numberOfQueries];
|
||||
NSMutableSet *requestIDs = [NSMutableSet setWithCapacity:numberOfQueries];
|
||||
NSMutableArray *requestIDs = [NSMutableSet setWithCapacity:numberOfQueries];
|
||||
for (GTLQuery *query in queries) {
|
||||
NSString *methodName = query.methodName;
|
||||
NSDictionary *parameters = query.JSON;
|
||||
@@ -772,6 +772,10 @@ static NSString *ETagIfPresent(GTLObject *obj) {
|
||||
@"additionalHTTPHeaders disallowed on queries added to a batch - query %@ (%@)",
|
||||
requestID, methodName);
|
||||
|
||||
GTL_DEBUG_ASSERT(query.urlQueryParameters == nil,
|
||||
@"urlQueryParameters disallowed on queries added to a batch - query %@ (%@)",
|
||||
requestID, methodName);
|
||||
|
||||
GTL_DEBUG_ASSERT(query.uploadParameters == nil,
|
||||
@"uploadParameters disallowed on queries added to a batch - query %@ (%@)",
|
||||
requestID, methodName);
|
||||
@@ -802,10 +806,16 @@ static NSString *ETagIfPresent(GTLObject *obj) {
|
||||
|
||||
BOOL mayAuthorize = (batchCopy ? !batchCopy.shouldSkipAuthorization : YES);
|
||||
|
||||
// urlQueryParameters on the queries are currently unsupport during a batch
|
||||
// as it's not clear how to map them.
|
||||
|
||||
NSURL *rpcURL = self.rpcURL;
|
||||
|
||||
// We'll use the batch query's URL parameters, and ignore the URL parameters
|
||||
// specified on the individual queries.
|
||||
NSDictionary *urlQueryParameters = batch.urlQueryParameters;
|
||||
if ([urlQueryParameters count] > 0) {
|
||||
rpcURL = [GTLUtilities URLWithString:[rpcURL absoluteString]
|
||||
queryParameters:urlQueryParameters];
|
||||
}
|
||||
|
||||
GTLServiceTicket *resultTicket = [self fetchObjectWithURL:rpcURL
|
||||
objectClass:[GTLBatchResult class]
|
||||
bodyObject:nil
|
||||
|
@@ -85,7 +85,9 @@
|
||||
// iOS 6 and Mac OS X 10.7, clients may simply create an operation queue for
|
||||
// callbacks on a background thread:
|
||||
//
|
||||
// fetcher.delegateQueue = [[[NSOperationQueue alloc] init] autorelease];
|
||||
// NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
|
||||
// [queue setMaxConcurrentOperationCount:1];
|
||||
// fetcher.delegateQueue = queue;
|
||||
//
|
||||
// or specify the main queue for callbacks on the main thread:
|
||||
//
|
||||
@@ -383,7 +385,7 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
|
||||
@protocol GTMFetcherAuthorizationProtocol <NSObject>
|
||||
@required
|
||||
// This protocol allows us to call the authorizer without requiring its sources
|
||||
// in this project
|
||||
// in this project.
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
delegate:(id)delegate
|
||||
didFinishSelector:(SEL)sel;
|
||||
@@ -396,12 +398,27 @@ NSString *GTMApplicationIdentifier(NSBundle *bundle);
|
||||
|
||||
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
||||
|
||||
- (NSString *)userEmail;
|
||||
@property (retain, readonly) NSString *userEmail;
|
||||
|
||||
@optional
|
||||
|
||||
// Indicate if authorization may be attempted. Even if this succeeds,
|
||||
// authorization may fail if the user's permissions have been revoked.
|
||||
@property (readonly) BOOL canAuthorize;
|
||||
|
||||
// For development only, allow authorization of non-SSL requests, allowing
|
||||
// transmission of the bearer token unencrypted.
|
||||
@property (assign) BOOL shouldAuthorizeAllRequests;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
completionHandler:(void (^)(NSError *error))handler;
|
||||
#endif
|
||||
|
||||
@property (assign) id <GTMHTTPFetcherServiceProtocol> fetcherService; // WEAK
|
||||
|
||||
- (BOOL)primeForRefresh;
|
||||
|
||||
@end
|
||||
|
||||
// GTMHTTPFetcher objects are used for async retrieval of an http get or post
|
||||
|
@@ -142,6 +142,11 @@ static NSString *const kCallbackError = @"error";
|
||||
// Default to system default cookie storage
|
||||
[self setCookieStorageMethod:kGTMHTTPFetcherCookieStorageMethodSystemDefault];
|
||||
}
|
||||
#if !STRIP_GTM_FETCH_LOGGING
|
||||
// Encourage developers to set the comment property or use
|
||||
// setCommentWithFormat: by providing a default string.
|
||||
comment_ = @"(No fetcher comment set)";
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -345,6 +350,13 @@ static NSString *const kCallbackError = @"error";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (downloadFileHandle_ != nil) {
|
||||
// Downloading to a file, so downloadedData_ remains nil.
|
||||
} else {
|
||||
self.downloadedData = [NSMutableData data];
|
||||
}
|
||||
|
||||
hasConnectionEnded_ = NO;
|
||||
if ([runLoopModes_ count] == 0 && delegateQueue == nil) {
|
||||
// No custom callback modes or queue were specified, so start the connection
|
||||
// on the current run loop in the current mode
|
||||
@@ -367,19 +379,13 @@ static NSString *const kCallbackError = @"error";
|
||||
}
|
||||
[connection_ start];
|
||||
}
|
||||
hasConnectionEnded_ = NO;
|
||||
|
||||
if (!connection_) {
|
||||
NSAssert(connection_ != nil, @"beginFetchWithDelegate could not create a connection");
|
||||
self.downloadedData = nil;
|
||||
goto CannotBeginFetch;
|
||||
}
|
||||
|
||||
if (downloadFileHandle_ != nil) {
|
||||
// downloading to a file, so downloadedData_ remains nil
|
||||
} else {
|
||||
self.downloadedData = [NSMutableData data];
|
||||
}
|
||||
|
||||
#if GTM_BACKGROUND_FETCHING
|
||||
backgroundTaskIdentifer_ = 0; // UIBackgroundTaskInvalid is 0 on iOS 4
|
||||
if (shouldFetchInBackground_) {
|
||||
@@ -388,15 +394,22 @@ static NSString *const kCallbackError = @"error";
|
||||
if ([app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)]) {
|
||||
// Tell UIApplication that we want to continue even when the app is in the
|
||||
// background.
|
||||
NSThread *thread = [NSThread currentThread];
|
||||
NSThread *thread = delegateQueue_ ? nil : [NSThread currentThread];
|
||||
backgroundTaskIdentifer_ = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||
// Callback - this block is always invoked by UIApplication on the main
|
||||
// thread, but we want to run the user's callbacks on the thread used
|
||||
// to start the fetch.
|
||||
[self performSelector:@selector(backgroundFetchExpired)
|
||||
onThread:thread
|
||||
withObject:nil
|
||||
waitUntilDone:YES];
|
||||
// Background task expiration callback - this block is always invoked by
|
||||
// UIApplication on the main thread.
|
||||
if (thread) {
|
||||
// Run the user's callbacks on the thread used to start the
|
||||
// fetch.
|
||||
[self performSelector:@selector(backgroundFetchExpired)
|
||||
onThread:thread
|
||||
withObject:nil
|
||||
waitUntilDone:YES];
|
||||
} else {
|
||||
// backgroundFetchExpired invokes callbacks on the provided delegate
|
||||
// queue.
|
||||
[self backgroundFetchExpired];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -673,7 +686,7 @@ CannotBeginFetch:
|
||||
// this may be called in a callback from the connection, so use autorelease
|
||||
[oldConnection autorelease];
|
||||
}
|
||||
}
|
||||
} // @synchronized(self)
|
||||
|
||||
// send the stopped notification
|
||||
[self sendStopNotificationIfNeeded];
|
||||
@@ -692,7 +705,7 @@ CannotBeginFetch:
|
||||
error:NULL];
|
||||
self.temporaryDownloadPath = nil;
|
||||
}
|
||||
}
|
||||
} // @synchronized(self)
|
||||
|
||||
[service fetcherDidStop:self];
|
||||
|
||||
@@ -824,7 +837,7 @@ CannotBeginFetch:
|
||||
[self setMutableRequest:mutable];
|
||||
}
|
||||
return redirectRequest;
|
||||
}
|
||||
} // @synchronized(self)
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
@@ -900,7 +913,7 @@ didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
forAuthenticationChallenge:challenge];
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // @synchronized(self)
|
||||
|
||||
// If we don't have credentials, or we've already failed auth 3x,
|
||||
// report the error, putting the challenge as a value in the userInfo
|
||||
@@ -1061,11 +1074,18 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
@synchronized(self) {
|
||||
#if DEBUG
|
||||
// The download file handle should be set before the fetch is started, not
|
||||
// after
|
||||
NSAssert(!hasConnectionEnded_, @"Connection received data after ending");
|
||||
|
||||
// The download file handle should be set or the data object allocated
|
||||
// before the fetch is started.
|
||||
NSAssert((downloadFileHandle_ == nil) != (downloadedData_ == nil),
|
||||
@"received data accumulates as NSData or NSFileHandle, not both");
|
||||
@"received data accumulates as either NSData (%d) or"
|
||||
@" NSFileHandle (%d)",
|
||||
(downloadedData_ != nil), (downloadFileHandle_ != nil));
|
||||
#endif
|
||||
// Hopefully, we'll never see this execute out-of-order, receiving data
|
||||
// after we've received the finished or failed callback.
|
||||
if (hasConnectionEnded_) return;
|
||||
|
||||
if (downloadFileHandle_ != nil) {
|
||||
// Append to file
|
||||
@@ -1102,7 +1122,7 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
receivedDataBlock_(downloadedData_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // @synchronized(self)
|
||||
}
|
||||
|
||||
// For error 304's ("Not Modified") where we've cached the data, return
|
||||
@@ -1228,7 +1248,7 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
#if !STRIP_GTM_FETCH_LOGGING
|
||||
shouldDeferLogging = shouldDeferResponseBodyLogging_;
|
||||
#endif
|
||||
}
|
||||
} // @synchronized(self)
|
||||
|
||||
if (shouldBeginRetryTimer) {
|
||||
[self beginRetryTimer];
|
||||
@@ -1470,7 +1490,7 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
retryTimer_ = nil;
|
||||
shouldNotify = YES;
|
||||
}
|
||||
}
|
||||
} // @synchronized(self)
|
||||
|
||||
if (shouldNotify) {
|
||||
NSNotificationCenter *defaultNC = [NSNotificationCenter defaultCenter];
|
||||
|
@@ -80,6 +80,7 @@ _EXTERN NSString* const kGTMOAuth2FetchTypeUserInfo _INITIALIZE_AS(@"userInfo"
|
||||
|
||||
// Token-issuance errors
|
||||
_EXTERN NSString* const kGTMOAuth2ErrorKey _INITIALIZE_AS(@"error");
|
||||
_EXTERN NSString* const kGTMOAuth2ErrorObjectKey _INITIALIZE_AS(@"kGTMOAuth2ErrorObjectKey");
|
||||
|
||||
_EXTERN NSString* const kGTMOAuth2ErrorInvalidRequest _INITIALIZE_AS(@"invalid_request");
|
||||
_EXTERN NSString* const kGTMOAuth2ErrorInvalidClient _INITIALIZE_AS(@"invalid_client");
|
||||
@@ -93,8 +94,9 @@ _EXTERN NSString* const kGTMOAuth2ErrorInvalidScope _INITIALIZE_AS(@"inv
|
||||
_EXTERN NSString* const kGTMOAuth2UserSignedIn _INITIALIZE_AS(@"kGTMOAuth2UserSignedIn");
|
||||
|
||||
// Notification for token changes
|
||||
_EXTERN NSString* const kGTMOAuth2AccessTokenRefreshed _INITIALIZE_AS(@"kGTMOAuth2AccessTokenRefreshed");
|
||||
_EXTERN NSString* const kGTMOAuth2RefreshTokenChanged _INITIALIZE_AS(@"kGTMOAuth2RefreshTokenChanged");
|
||||
_EXTERN NSString* const kGTMOAuth2AccessTokenRefreshed _INITIALIZE_AS(@"kGTMOAuth2AccessTokenRefreshed");
|
||||
_EXTERN NSString* const kGTMOAuth2RefreshTokenChanged _INITIALIZE_AS(@"kGTMOAuth2RefreshTokenChanged");
|
||||
_EXTERN NSString* const kGTMOAuth2AccessTokenRefreshFailed _INITIALIZE_AS(@"kGTMOAuth2AccessTokenRefreshFailed");
|
||||
|
||||
// Notification for WebView loading
|
||||
_EXTERN NSString* const kGTMOAuth2WebViewStartedLoading _INITIALIZE_AS(@"kGTMOAuth2WebViewStartedLoading");
|
||||
@@ -120,7 +122,10 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
|
||||
NSURL *tokenURL_;
|
||||
NSDate *expirationDate_;
|
||||
|
||||
NSString *authorizationTokenKey_;
|
||||
|
||||
NSDictionary *additionalTokenRequestParameters_;
|
||||
NSDictionary *additionalGrantTypeRequestParameters_;
|
||||
|
||||
// queue of requests for authorization waiting for a valid access token
|
||||
GTMHTTPFetcher *refreshFetcher_;
|
||||
@@ -152,9 +157,20 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
|
||||
@property (retain) NSString *refreshScope;
|
||||
|
||||
// Apps may optionally add parameters here to be provided to the token
|
||||
// endpoint on token requests and refreshes
|
||||
// endpoint on token requests and refreshes.
|
||||
@property (retain) NSDictionary *additionalTokenRequestParameters;
|
||||
|
||||
// Apps may optionally add parameters here to be provided to the token
|
||||
// endpoint on specific token requests and refreshes, keyed by the grant_type.
|
||||
// For example, if a different "type" parameter is required for obtaining
|
||||
// the auth code and on refresh, this might be:
|
||||
//
|
||||
// viewController.authentication.additionalGrantTypeRequestParameters = @{
|
||||
// @"authorization_code" : @{ @"type" : @"code" },
|
||||
// @"refresh_token" : @{ @"type" : @"refresh" }
|
||||
// };
|
||||
@property (retain) NSDictionary *additionalGrantTypeRequestParameters;
|
||||
|
||||
// Response properties
|
||||
@property (retain) NSMutableDictionary *parameters;
|
||||
|
||||
@@ -216,6 +232,11 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
|
||||
// not set, the class SBJSON must be available in the runtime.
|
||||
@property (assign) Class parserClass;
|
||||
|
||||
// Key for the response parameter used for the authorization header; by default,
|
||||
// "access_token" is used, but some servers may expect alternatives, like
|
||||
// "id_token".
|
||||
@property (copy) NSString *authorizationTokenKey;
|
||||
|
||||
// Convenience method for creating an authentication object
|
||||
+ (id)authenticationWithServiceProvider:(NSString *)serviceProvider
|
||||
tokenURL:(NSURL *)tokenURL
|
||||
@@ -327,6 +348,8 @@ _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuth
|
||||
|
||||
+ (NSDictionary *)dictionaryWithResponseString:(NSString *)responseStr;
|
||||
|
||||
+ (NSDictionary *)dictionaryWithJSONData:(NSData *)data;
|
||||
|
||||
+ (NSString *)scopeWithStrings:(NSString *)firsStr, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
@end
|
||||
|
||||
|
@@ -122,6 +122,7 @@ static NSString *const kRefreshFetchArgsKey = @"requestArgs";
|
||||
@interface GTMOAuth2Authentication ()
|
||||
|
||||
@property (retain) NSMutableArray *authorizationQueue;
|
||||
@property (readonly) NSString *authorizationToken;
|
||||
|
||||
- (void)setKeysForResponseJSONData:(NSData *)data;
|
||||
|
||||
@@ -133,8 +134,6 @@ static NSString *const kRefreshFetchArgsKey = @"requestArgs";
|
||||
|
||||
- (void)updateExpirationDate;
|
||||
|
||||
- (NSDictionary *)dictionaryWithJSONData:(NSData *)data;
|
||||
|
||||
- (void)tokenFetcher:(GTMHTTPFetcher *)fetcher
|
||||
finishedWithData:(NSData *)data
|
||||
error:(NSError *)error;
|
||||
@@ -164,9 +163,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
clientSecret = clientSecret_,
|
||||
redirectURI = redirectURI_,
|
||||
parameters = parameters_,
|
||||
authorizationTokenKey = authorizationTokenKey_,
|
||||
tokenURL = tokenURL_,
|
||||
expirationDate = expirationDate_,
|
||||
additionalTokenRequestParameters = additionalTokenRequestParameters_,
|
||||
additionalGrantTypeRequestParameters = additionalGrantTypeRequestParameters_,
|
||||
refreshFetcher = refreshFetcher_,
|
||||
fetcherService = fetcherService_,
|
||||
parserClass = parserClass_,
|
||||
@@ -237,9 +238,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
[clientSecret_ release];
|
||||
[redirectURI_ release];
|
||||
[parameters_ release];
|
||||
[authorizationTokenKey_ release];
|
||||
[tokenURL_ release];
|
||||
[expirationDate_ release];
|
||||
[additionalTokenRequestParameters_ release];
|
||||
[additionalGrantTypeRequestParameters_ release];
|
||||
[refreshFetcher_ release];
|
||||
[authorizationQueue_ release];
|
||||
[userData_ release];
|
||||
@@ -290,11 +293,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
}
|
||||
|
||||
- (void)setKeysForResponseJSONData:(NSData *)data {
|
||||
NSDictionary *dict = [self dictionaryWithJSONData:data];
|
||||
NSDictionary *dict = [[self class] dictionaryWithJSONData:data];
|
||||
[self setKeysForResponseDictionary:dict];
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryWithJSONData:(NSData *)data {
|
||||
+ (NSDictionary *)dictionaryWithJSONData:(NSData *)data {
|
||||
NSMutableDictionary *obj = nil;
|
||||
NSError *error = nil;
|
||||
|
||||
@@ -437,12 +440,32 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
|
||||
BOOL hasAccessToken = ([self.accessToken length] > 0);
|
||||
|
||||
NSString *noteName;
|
||||
NSDictionary *userInfo = nil;
|
||||
if (hasAccessToken && error == nil) {
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:kGTMOAuth2AccessTokenRefreshed
|
||||
object:self
|
||||
userInfo:nil];
|
||||
// Successful refresh.
|
||||
noteName = kGTMOAuth2AccessTokenRefreshed;
|
||||
userInfo = nil;
|
||||
} else {
|
||||
// Google's OAuth 2 implementation returns a 400 with JSON body
|
||||
// containing error key "invalid_grant" to indicate the refresh token
|
||||
// is invalid or has been revoked by the user. We'll promote the
|
||||
// JSON error key's value for easy inspection by the observer.
|
||||
noteName = kGTMOAuth2AccessTokenRefreshFailed;
|
||||
NSString *jsonErr = nil;
|
||||
if ([error code] == kGTMHTTPFetcherStatusBadRequest) {
|
||||
NSDictionary *json = [[error userInfo] objectForKey:kGTMOAuth2ErrorJSONKey];
|
||||
jsonErr = [json objectForKey:kGTMOAuth2ErrorMessageKey];
|
||||
}
|
||||
// error and jsonErr may be nil
|
||||
userInfo = [NSMutableDictionary dictionary];
|
||||
[userInfo setValue:error forKey:kGTMOAuth2ErrorObjectKey];
|
||||
[userInfo setValue:jsonErr forKey:kGTMOAuth2ErrorMessageKey];
|
||||
}
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:noteName
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
|
||||
for (GTMOAuth2AuthorizationArgs *args in pendingAuthQueue) {
|
||||
if (!hasAccessToken && args.error == nil) {
|
||||
@@ -522,7 +545,8 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
#endif
|
||||
}
|
||||
|
||||
NSString *accessToken = self.accessToken;
|
||||
// Get the access token.
|
||||
NSString *accessToken = self.authorizationToken;
|
||||
if (isAuthorizableRequest && [accessToken length] > 0) {
|
||||
if (request) {
|
||||
// we have a likely valid access token
|
||||
@@ -620,8 +644,8 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
NSString *token = self.refreshToken;
|
||||
if (token == nil) {
|
||||
// For services which do not support refresh tokens, we'll just check
|
||||
// the access token
|
||||
token = self.accessToken;
|
||||
// the access token.
|
||||
token = self.authorizationToken;
|
||||
}
|
||||
BOOL canAuth = [token length] > 0;
|
||||
return canAuth;
|
||||
@@ -699,10 +723,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
NSString *refreshToken = self.refreshToken;
|
||||
NSString *code = self.code;
|
||||
NSString *assertion = self.assertion;
|
||||
NSString *grantType = nil;
|
||||
|
||||
if (refreshToken) {
|
||||
// We have a refresh token
|
||||
[paramsDict setObject:@"refresh_token" forKey:@"grant_type"];
|
||||
grantType = @"refresh_token";
|
||||
[paramsDict setObject:refreshToken forKey:@"refresh_token"];
|
||||
|
||||
NSString *refreshScope = self.refreshScope;
|
||||
@@ -713,7 +738,7 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
fetchType = kGTMOAuth2FetchTypeRefresh;
|
||||
} else if (code) {
|
||||
// We have a code string
|
||||
[paramsDict setObject:@"authorization_code" forKey:@"grant_type"];
|
||||
grantType = @"authorization_code";
|
||||
[paramsDict setObject:code forKey:@"code"];
|
||||
|
||||
NSString *redirectURI = self.redirectURI;
|
||||
@@ -729,9 +754,8 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
fetchType = kGTMOAuth2FetchTypeToken;
|
||||
} else if (assertion) {
|
||||
// We have an assertion string
|
||||
grantType = @"http://oauth.net/grant_type/jwt/1.0/bearer";
|
||||
[paramsDict setObject:assertion forKey:@"assertion"];
|
||||
[paramsDict setObject:@"http://oauth.net/grant_type/jwt/1.0/bearer"
|
||||
forKey:@"grant_type"];
|
||||
fetchType = kGTMOAuth2FetchTypeAssertion;
|
||||
} else {
|
||||
#if DEBUG
|
||||
@@ -739,7 +763,8 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
#endif
|
||||
return nil;
|
||||
}
|
||||
|
||||
[paramsDict setObject:grantType forKey:@"grant_type"];
|
||||
|
||||
NSString *clientID = self.clientID;
|
||||
if ([clientID length] > 0) {
|
||||
[paramsDict setObject:clientID forKey:@"client_id"];
|
||||
@@ -754,6 +779,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
if (additionalParams) {
|
||||
[paramsDict addEntriesFromDictionary:additionalParams];
|
||||
}
|
||||
NSDictionary *grantTypeParams =
|
||||
[self.additionalGrantTypeRequestParameters objectForKey:grantType];
|
||||
if (grantTypeParams) {
|
||||
[paramsDict addEntriesFromDictionary:grantTypeParams];
|
||||
}
|
||||
|
||||
NSString *paramStr = [[self class] encodedQueryParametersForDictionary:paramsDict];
|
||||
NSData *paramData = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@@ -821,11 +851,11 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
BOOL hasData = ([data length] > 0);
|
||||
|
||||
if (error) {
|
||||
// Failed; if the error body is JSON, parse it and add it to the error's
|
||||
// userInfo dictionary
|
||||
// Failed. If the error body is JSON, parse it and add it to the error's
|
||||
// userInfo dictionary.
|
||||
if (hasData) {
|
||||
if (isResponseJSON) {
|
||||
NSDictionary *errorJson = [self dictionaryWithJSONData:data];
|
||||
NSDictionary *errorJson = [[self class] dictionaryWithJSONData:data];
|
||||
if ([errorJson count] > 0) {
|
||||
#if DEBUG
|
||||
NSLog(@"Error %@\nError data:\n%@", error, errorJson);
|
||||
@@ -845,7 +875,7 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Succeeded; we have an access token
|
||||
// Succeeded; we have the requested token.
|
||||
#if DEBUG
|
||||
NSAssert(hasData, @"data missing in token response");
|
||||
#endif
|
||||
@@ -960,10 +990,24 @@ finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
self.expirationDate = nil;
|
||||
self.userEmail = nil;
|
||||
self.userEmailIsVerified = nil;
|
||||
self.authorizationTokenKey = nil;
|
||||
}
|
||||
|
||||
#pragma mark Accessors for Response Parameters
|
||||
|
||||
- (NSString *)authorizationToken {
|
||||
// The token used for authorization is typically the access token unless
|
||||
// the user has specified that an alternative parameter be used.
|
||||
NSString *authorizationToken;
|
||||
NSString *authTokenKey = self.authorizationTokenKey;
|
||||
if (authTokenKey != nil) {
|
||||
authorizationToken = [self.parameters objectForKey:authTokenKey];
|
||||
} else {
|
||||
authorizationToken = self.accessToken;
|
||||
}
|
||||
return authorizationToken;
|
||||
}
|
||||
|
||||
- (NSString *)accessToken {
|
||||
return [self.parameters objectForKey:kOAuth2AccessTokenKey];
|
||||
}
|
||||
|
@@ -29,10 +29,6 @@ static const NSTimeInterval kDefaultNetworkLossTimeoutInterval = 30.0;
|
||||
NSString *const kOOBString = @"urn:ietf:wg:oauth:2.0:oob";
|
||||
|
||||
|
||||
@interface GTMOAuth2Authentication (InternalMethods)
|
||||
- (NSDictionary *)dictionaryWithJSONData:(NSData *)data;
|
||||
@end
|
||||
|
||||
@interface GTMOAuth2SignIn ()
|
||||
@property (assign) BOOL hasHandledCallback;
|
||||
@property (retain) GTMHTTPFetcher *pendingFetcher;
|
||||
@@ -68,6 +64,8 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
- (void)reachabilityTarget:(SCNetworkReachabilityRef)reachabilityRef
|
||||
changedFlags:(SCNetworkConnectionFlags)flags;
|
||||
- (void)reachabilityTimerFired:(NSTimer *)timer;
|
||||
|
||||
+ (NSData *)decodeWebSafeBase64:(NSString *)base64Str;
|
||||
@end
|
||||
|
||||
@implementation GTMOAuth2SignIn
|
||||
@@ -559,12 +557,17 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
NSURL *infoURL = [[self class] googleUserInfoURL];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:infoURL];
|
||||
|
||||
NSString *userAgent = [auth userAgent];
|
||||
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||
if ([auth respondsToSelector:@selector(userAgent)]) {
|
||||
NSString *userAgent = [auth userAgent];
|
||||
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||
}
|
||||
[request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];
|
||||
|
||||
GTMHTTPFetcher *fetcher;
|
||||
id <GTMHTTPFetcherServiceProtocol> fetcherService = auth.fetcherService;
|
||||
id <GTMHTTPFetcherServiceProtocol> fetcherService = nil;
|
||||
if ([auth respondsToSelector:@selector(fetcherService)]) {
|
||||
fetcherService = auth.fetcherService;
|
||||
};
|
||||
if (fetcherService) {
|
||||
fetcher = [fetcherService fetcherWithRequest:request];
|
||||
} else {
|
||||
@@ -578,7 +581,36 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
}
|
||||
|
||||
- (void)fetchGoogleUserInfo {
|
||||
// fetch the user's email address or profile
|
||||
if (!self.shouldFetchGoogleUserProfile) {
|
||||
// If we only need email and user ID, not the full profile, and we have an
|
||||
// id_token, it may have the email and user ID so we won't need to fetch
|
||||
// them.
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSString *idToken = [auth.parameters objectForKey:@"id_token"];
|
||||
if ([idToken length] > 0) {
|
||||
// The id_token has three dot-delimited parts. The second is the
|
||||
// JSON profile.
|
||||
//
|
||||
// http://www.tbray.org/ongoing/When/201x/2013/04/04/ID-Tokens
|
||||
NSArray *parts = [idToken componentsSeparatedByString:@"."];
|
||||
if ([parts count] == 3) {
|
||||
NSString *part2 = [parts objectAtIndex:1];
|
||||
if ([part2 length] > 0) {
|
||||
NSData *data = [[self class] decodeWebSafeBase64:part2];
|
||||
if ([data length] > 0) {
|
||||
[self updateGoogleUserInfoWithData:data];
|
||||
if ([[auth userID] length] > 0 && [[auth userEmail] length] > 0) {
|
||||
// We obtained user ID and email from the ID token.
|
||||
[self finishSignInWithError:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the email and profile from the userinfo endpoint.
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
GTMHTTPFetcher *fetcher = [[self class] userInfoFetcherWithAuth:auth];
|
||||
[fetcher beginFetchWithDelegate:self
|
||||
@@ -611,27 +643,40 @@ finishedWithFetcher:(GTMHTTPFetcher *)fetcher
|
||||
#endif
|
||||
} else {
|
||||
// We have the authenticated user's info
|
||||
if (data) {
|
||||
NSDictionary *profileDict = [auth dictionaryWithJSONData:data];
|
||||
if (profileDict) {
|
||||
self.userProfile = profileDict;
|
||||
|
||||
// Save the ID into the auth object
|
||||
NSString *identifier = [profileDict objectForKey:@"id"];
|
||||
[auth setUserID:identifier];
|
||||
|
||||
// Save the email into the auth object
|
||||
NSString *email = [profileDict objectForKey:@"email"];
|
||||
[auth setUserEmail:email];
|
||||
|
||||
NSNumber *verified = [profileDict objectForKey:@"verified_email"];
|
||||
[auth setUserEmailIsVerified:[verified stringValue]];
|
||||
}
|
||||
}
|
||||
[self updateGoogleUserInfoWithData:data];
|
||||
}
|
||||
[self finishSignInWithError:error];
|
||||
}
|
||||
|
||||
- (void)updateGoogleUserInfoWithData:(NSData *)data {
|
||||
if (!data) return;
|
||||
|
||||
GTMOAuth2Authentication *auth = self.authentication;
|
||||
NSDictionary *profileDict = [[auth class] dictionaryWithJSONData:data];
|
||||
if (profileDict) {
|
||||
self.userProfile = profileDict;
|
||||
|
||||
// Save the ID into the auth object
|
||||
NSString *identifier = [profileDict objectForKey:@"id"];
|
||||
[auth setUserID:identifier];
|
||||
|
||||
// Save the email into the auth object
|
||||
NSString *email = [profileDict objectForKey:@"email"];
|
||||
[auth setUserEmail:email];
|
||||
|
||||
// The verified_email key is a boolean NSNumber in the userinfo
|
||||
// endpoint response, but it is a string like "true" in the id_token.
|
||||
// We want to consistently save it as a string of the boolean value,
|
||||
// like @"1".
|
||||
id verified = [profileDict objectForKey:@"verified_email"];
|
||||
if ([verified isKindOfClass:[NSString class]]) {
|
||||
verified = [NSNumber numberWithBool:[verified boolValue]];
|
||||
}
|
||||
|
||||
[auth setUserEmailIsVerified:[verified stringValue]];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
|
||||
- (void)finishSignInWithError:(NSError *)error {
|
||||
@@ -828,6 +873,62 @@ static void ReachabilityCallBack(SCNetworkReachabilityRef target,
|
||||
}
|
||||
[auth reset];
|
||||
}
|
||||
|
||||
|
||||
// Based on Cyrus Najmabadi's elegent little encoder and decoder from
|
||||
// http://www.cocoadev.com/index.pl?BaseSixtyFour and on GTLBase64
|
||||
|
||||
+ (NSData *)decodeWebSafeBase64:(NSString *)base64Str {
|
||||
static char decodingTable[128];
|
||||
static BOOL hasInited = NO;
|
||||
|
||||
if (!hasInited) {
|
||||
char webSafeEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
memset(decodingTable, 0, 128);
|
||||
for (unsigned int i = 0; i < sizeof(webSafeEncodingTable); i++) {
|
||||
decodingTable[(unsigned int) webSafeEncodingTable[i]] = (char)i;
|
||||
}
|
||||
hasInited = YES;
|
||||
}
|
||||
|
||||
// The input string should be plain ASCII.
|
||||
const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
if (cString == nil) return nil;
|
||||
|
||||
NSInteger inputLength = (NSInteger)strlen(cString);
|
||||
// Input length is not being restricted to multiples of 4.
|
||||
if (inputLength == 0) return [NSData data];
|
||||
|
||||
while (inputLength > 0 && cString[inputLength - 1] == '=') {
|
||||
inputLength--;
|
||||
}
|
||||
|
||||
NSInteger outputLength = inputLength * 3 / 4;
|
||||
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)outputLength];
|
||||
uint8_t *output = [data mutableBytes];
|
||||
|
||||
NSInteger inputPoint = 0;
|
||||
NSInteger outputPoint = 0;
|
||||
char *table = decodingTable;
|
||||
|
||||
while (inputPoint < inputLength - 1) {
|
||||
int i0 = cString[inputPoint++];
|
||||
int i1 = cString[inputPoint++];
|
||||
int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0
|
||||
int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A';
|
||||
|
||||
output[outputPoint++] = (uint8_t)((table[i0] << 2) | (table[i1] >> 4));
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = (uint8_t)(((table[i1] & 0xF) << 4) | (table[i2] >> 2));
|
||||
}
|
||||
if (outputPoint < outputLength) {
|
||||
output[outputPoint++] = (uint8_t)(((table[i2] & 0x3) << 6) | table[i3]);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT
|
||||
|
||||
@end
|
||||
|
@@ -45,10 +45,11 @@
|
||||
|
||||
_EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com.google.GTMOAuthKeychain");
|
||||
|
||||
|
||||
@class GTMOAuth2SignIn;
|
||||
@class GTMOAuth2ViewControllerTouch;
|
||||
|
||||
typedef void (^GTMOAuth2ViewControllerCompletionHandler)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error);
|
||||
|
||||
@interface GTMOAuth2ViewControllerTouch : UIViewController<UINavigationControllerDelegate, UIWebViewDelegate> {
|
||||
@private
|
||||
UIButton *backButton_;
|
||||
@@ -73,7 +74,7 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
|
||||
SEL finishedSelector_;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
void (^completionBlock_)(GTMOAuth2ViewControllerTouch *, GTMOAuth2Authentication *, NSError *);
|
||||
GTMOAuth2ViewControllerCompletionHandler completionBlock_;
|
||||
|
||||
void (^popViewBlock_)(void);
|
||||
#endif
|
||||
@@ -168,7 +169,7 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
|
||||
#endif
|
||||
|
||||
// the default timeout for an unreachable network during display of the
|
||||
// sign-in page is 10 seconds; set this to 0 to have no timeout
|
||||
// sign-in page is 30 seconds; set this to 0 to have no timeout
|
||||
@property (nonatomic, assign) NSTimeInterval networkLossTimeoutInterval;
|
||||
|
||||
// if set, cookies are deleted for this URL when the view is hidden
|
||||
@@ -228,13 +229,13 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler;
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
|
||||
- (id)initWithScope:(NSString *)scope
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler;
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -257,12 +258,12 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
|
||||
+ (id)controllerWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName // may be nil
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler;
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler;
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler;
|
||||
#endif
|
||||
|
||||
// subclasses may override authNibName to specify a custom name
|
||||
@@ -271,6 +272,10 @@ _EXTERN NSString* const kGTMOAuth2KeychainErrorDomain _INITIALIZE_AS(@"com
|
||||
// subclasses may override authNibBundle to specify a custom bundle
|
||||
+ (NSBundle *)authNibBundle;
|
||||
|
||||
// subclasses may override setUpNavigation to provide their own navigation
|
||||
// controls
|
||||
- (void)setUpNavigation;
|
||||
|
||||
// apps may replace the sign-in class with their own subclass of it
|
||||
+ (Class)signInClass;
|
||||
+ (void)setSignInClass:(Class)theClass;
|
||||
|
@@ -113,7 +113,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler {
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler {
|
||||
return [[[self alloc] initWithScope:scope
|
||||
clientID:clientID
|
||||
clientSecret:clientSecret
|
||||
@@ -125,7 +125,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler {
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler {
|
||||
// convenient entry point for Google authentication
|
||||
|
||||
Class signInClass = [[self class] signInClass];
|
||||
@@ -206,7 +206,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
+ (id)controllerWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler {
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler {
|
||||
return [[[self alloc] initWithAuthentication:auth
|
||||
authorizationURL:authorizationURL
|
||||
keychainItemName:keychainItemName
|
||||
@@ -216,7 +216,7 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
- (id)initWithAuthentication:(GTMOAuth2Authentication *)auth
|
||||
authorizationURL:(NSURL *)authorizationURL
|
||||
keychainItemName:(NSString *)keychainItemName
|
||||
completionHandler:(void (^)(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error))handler {
|
||||
completionHandler:(GTMOAuth2ViewControllerCompletionHandler)handler {
|
||||
// fall back to the non-blocks init
|
||||
self = [self initWithAuthentication:auth
|
||||
authorizationURL:authorizationURL
|
||||
@@ -365,6 +365,10 @@ finishedWithAuth:(GTMOAuth2Authentication *)auth
|
||||
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[self setUpNavigation];
|
||||
}
|
||||
|
||||
- (void)setUpNavigation {
|
||||
rightBarButtonItem_.customView = navButtonsView_;
|
||||
self.navigationItem.rightBarButtonItem = rightBarButtonItem_;
|
||||
}
|
||||
@@ -670,6 +674,9 @@ static Class gSignInClass = Nil;
|
||||
#pragma mark Protocol implementations
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
// See the comment on clearBrowserCookies in viewDidDisappear.
|
||||
[self clearBrowserCookies];
|
||||
|
||||
if (!isViewShown_) {
|
||||
isViewShown_ = YES;
|
||||
if ([self isNavigationBarTranslucent]) {
|
||||
@@ -713,13 +720,18 @@ static Class gSignInClass = Nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
// prevent the next sign-in from showing in the WebView that the user is
|
||||
// already signed in
|
||||
[self clearBrowserCookies];
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
// prevent the next sign-in from showing in the WebView that the user is
|
||||
// already signed in. It's possible for the WebView to set the cookies even
|
||||
// after this, so we also clear them when the view first appears.
|
||||
[self clearBrowserCookies];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews {
|
||||
// We don't call super's version of this method because
|
||||
// -[UIViewController viewDidLayoutSubviews] is documented as a no-op, that
|
||||
|
44
External/google-plus-ios-sdk/OpenSource/GoogleOpenSource.h
vendored
Normal file
44
External/google-plus-ios-sdk/OpenSource/GoogleOpenSource.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// GoogleOpenSource.h
|
||||
// Google+ iOS SDK
|
||||
//
|
||||
// Copyright 2013 Google Inc.
|
||||
//
|
||||
// Use of this SDK is subject to the Google+ Platform Terms of Service:
|
||||
// https://developers.google.com/+/terms
|
||||
//
|
||||
|
||||
|
||||
// GTM.
|
||||
#import "GTMDefines.h"
|
||||
#import "GTMHTTPFetcher.h"
|
||||
#import "GTMHTTPFetcherService.h"
|
||||
#import "GTMHTTPFetchHistory.h"
|
||||
#import "GTMLogger.h"
|
||||
#import "GTMMethodCheck.h"
|
||||
#import "GTMNSDictionary+URLArguments.h"
|
||||
#import "GTMNSString+URLArguments.h"
|
||||
#import "GTMOAuth2Authentication.h"
|
||||
#import "GTMOAuth2SignIn.h"
|
||||
#import "GTMOAuth2ViewControllerTouch.h"
|
||||
#import "GTMObjC2Runtime.h"
|
||||
|
||||
// Chrome.
|
||||
#import "OpenInChromeController.h"
|
||||
|
||||
// GTL.
|
||||
#import "GTLDefines.h"
|
||||
#import "GTLBatchQuery.h"
|
||||
#import "GTLBatchResult.h"
|
||||
#import "GTLDateTime.h"
|
||||
#import "GTLErrorObject.h"
|
||||
#import "GTLObject.h"
|
||||
#import "GTLQuery.h"
|
||||
#import "GTLRuntimeCommon.h"
|
||||
#import "GTLService.h"
|
||||
#import "GTLFramework.h"
|
||||
#import "GTLJSONParser.h"
|
||||
#import "GTLUtilities.h"
|
||||
|
||||
// GTLPlus.
|
||||
#import "GTLPlus.h"
|
Reference in New Issue
Block a user