diff options
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/GTMAppAuth/Source')
9 files changed, 1578 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuth.h b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuth.h new file mode 100644 index 00000000..ecbdad60 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuth.h @@ -0,0 +1,30 @@ +/*! @file GTMAppAuth.h + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMAppAuthFetcherAuthorization.h" +#import "GTMAppAuthFetcherAuthorization+Keychain.h" + +#if TARGET_OS_TV +#elif TARGET_OS_WATCH +#elif TARGET_OS_IOS +#import "GTMOAuth2KeychainCompatibility.h" +#elif TARGET_OS_MAC +#import "GTMOAuth2KeychainCompatibility.h" +#else +#warn "Platform Undefined" +#endif diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.h b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.h new file mode 100644 index 00000000..f0b9ffeb --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.h @@ -0,0 +1,52 @@ +/*! @file GTMAppAuthFetcherAuthorization+Keychain.h + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMAppAuthFetcherAuthorization.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! @brief Category to support serialization and deserialization of + @c GTMAppAuthFetcherAuthorization in the format used by GTMAppAuth. + */ +@interface GTMAppAuthFetcherAuthorization (Keychain) + +/*! @brief Attempts to create a @c GTMAppAuthFetcherAuthorization from data stored in the keychain + in GTMAppAuth format. + @param keychainItemName The keychain name. + @return A @c GTMAppAuthFetcherAuthorization object, or nil. + */ ++ (nullable GTMAppAuthFetcherAuthorization *) + authorizationFromKeychainForName:(NSString *)keychainItemName; + +/*! @brief Removes a stored authorization state. + @param keychainItemName The keychain name. + @return YES the tokens were removed successfully (or didn't exist). + */ ++ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName; + +/*! @brief Saves the authorization state to the keychain, in GTMAppAuth format. + @param auth The authorization to save. + @param keychainItemName The keychain name. + @return YES when the state was saved successfully. + */ ++ (BOOL)saveAuthorization:(GTMAppAuthFetcherAuthorization *)auth + toKeychainForName:(NSString *)keychainItemName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.m b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.m new file mode 100644 index 00000000..e4910a81 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization+Keychain.m @@ -0,0 +1,46 @@ +/*! @file GTMAppAuthFetcherAuthorization+Keychain.m + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMAppAuthFetcherAuthorization+Keychain.h" + +#import "GTMKeychain.h" + +@implementation GTMAppAuthFetcherAuthorization (Keychain) + ++ (GTMAppAuthFetcherAuthorization *)authorizationFromKeychainForName:(NSString *)keychainItemName { + NSData *passwordData = [GTMKeychain passwordDataFromKeychainForName:keychainItemName]; + if (!passwordData) { + return nil; + } + GTMAppAuthFetcherAuthorization *authorization = (GTMAppAuthFetcherAuthorization *) + [NSKeyedUnarchiver unarchiveObjectWithData:passwordData]; + return authorization; +} + ++ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName { + return [GTMKeychain removePasswordFromKeychainForName:keychainItemName]; +} + ++ (BOOL)saveAuthorization:(GTMAppAuthFetcherAuthorization *)auth + toKeychainForName:(NSString *)keychainItemName { + NSData *authorizationData = [NSKeyedArchiver archivedDataWithRootObject:auth]; + return [GTMKeychain savePasswordDataToKeychainForName:keychainItemName + passwordData:authorizationData]; +} + +@end diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.h b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.h new file mode 100644 index 00000000..248223c8 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.h @@ -0,0 +1,153 @@ +/*! @file GTMAppAuthFetcherAuthorization.h + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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. + */ + +#ifndef GTMAPPAUTH_USER_IMPORTS +#import <GTMSessionFetcher/GTMSessionFetcher.h> +#else // GTMAPPAUTH_USER_IMPORTS +#import "GTMSessionFetcher.h" +#endif // GTMAPPAUTH_USER_IMPORTS + +@class OIDAuthState; +@class OIDServiceConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/*! @brief The userInfo key for the @c NSURLRequest. + */ +extern NSString *const GTMAppAuthFetcherAuthorizationErrorRequestKey; + +/*! @brief The error domain for errors specific to the session fetcher authorization. + */ +extern NSString *const GTMAppAuthFetcherAuthorizationErrorDomain; + +/*! @brief Enum of all possible error codes in the @c ::GTMAppAuthFetcherAuthorizationErrorDomain + domain. + @discussion Note that these are GTMAppAuth-specific errors. When AppAuth errors are encountered, + those are returned instead. + */ +typedef NS_ENUM(NSInteger, GTMAppAuthFetcherAuthorizationError) { + GTMAppAuthFetcherAuthorizationErrorUnauthorizableRequest = -1004 +}; + +typedef void (^GTMAppAuthFetcherAuthorizationCompletion)(NSError *_Nullable error); + +@class GTMAppAuthFetcherAuthorization; + +/*! @protocol GTMAppAuthFetcherAuthorizationTokenRefreshDelegate + @brief Delegate of the GTMAppAuthFetcherAuthorization used to supply additional parameters on + token refresh. + */ +@protocol GTMAppAuthFetcherAuthorizationTokenRefreshDelegate <NSObject> + +/*! @brief Called before a token refresh request is performed. + @param authorization The @c GTMFetcherAuthorization performing the token refresh. + @return A dictionary of parameters to be added to the token refresh request. + */ +- (nullable NSDictionary<NSString *, NSString *> *)additionalRefreshParameters: + (GTMAppAuthFetcherAuthorization *)authorization; + +@end + +/*! @brief An implementation of the @c GTMFetcherAuthorizationProtocol protocol for the AppAuth + library. + @discussion Enables you to use AppAuth with the GTM Session Fetcher library. + */ +@interface GTMAppAuthFetcherAuthorization : NSObject <GTMFetcherAuthorizationProtocol, + NSSecureCoding> + +/*! @brief The AppAuth authentication state. + */ +@property(nonatomic, readonly) OIDAuthState *authState; + +/*! @brief Service identifier, for example "Google"; not used for authentication. + @discussion The provider name is just for allowing stored authorization to be associated + with the authorizing service. + */ +@property(nullable, nonatomic, readonly) NSString *serviceProvider; + +/*! @brief User ID from the ID Token. + * @discussion Note: Never send this value to your backend as an authentication token, rather send + * an ID Token and validate it. + */ +@property(nullable, nonatomic, readonly) NSString *userID; + +/*! @brief Email verified status; not used for authentication. + @discussion The verified string can be checked with -boolValue. If the result is false, then + the email address is listed with the account on the server, but the address has not been + confirmed as belonging to the owner of the account. + */ +@property(nullable, nonatomic, readonly) NSString *userEmailIsVerified; + +@property(nullable, nonatomic, weak) id<GTMAppAuthFetcherAuthorizationTokenRefreshDelegate> + tokenRefreshDelegate; + +/*! @brief Creates a new @c GTMAppAuthFetcherAuthorization using the given @c OIDAuthState from + AppAuth. + @param authState The authorization state. + */ +- (instancetype)initWithAuthState:(OIDAuthState *)authState; + +/*! @brief Creates a new @c GTMAppAuthFetcherAuthorization using the given @c OIDAuthState from + AppAuth. + @param authState The authorization state. + @param serviceProvider An optional string to describe the service. + @param userID An optional string of the user ID. + @param userEmail An optional string of the user's email address. + @param userEmailIsVerified An optional string representation of a boolean to indicate that the + email address has been verified. Pass @"true" for @c YES, or @"false" for @c NO. + @discussion Designated initializer. + */ +- (instancetype)initWithAuthState:(OIDAuthState *)authState + serviceProvider:(nullable NSString *)serviceProvider + userID:(nullable NSString *)userID + userEmail:(nullable NSString *)userEmail + userEmailIsVerified:(nullable NSString *)userEmailIsVerified + NS_DESIGNATED_INITIALIZER; + +#if !GTM_APPAUTH_SKIP_GOOGLE_SUPPORT +/*! @brief Convenience method to return an @c OIDServiceConfiguration for Google. + @return A @c OIDServiceConfiguration object setup with Google OAuth endpoints. + */ ++ (OIDServiceConfiguration *)configurationForGoogle; +#endif // !GTM_APPAUTH_SKIP_GOOGLE_SUPPORT + +/*! @brief Adds an authorization header to the given request, using the authorization state. + Refreshes the access token if needed. + @param request The request to authorize. + @param handler The block that is called after authorizing the request is attempted. If @c error + is non-nil, the authorization failed. Errors in the domain @c ::OIDOAuthTokenErrorDomain + indicate that the authorization itself is invalid, and will need to be re-obtained from the + user. Errors in the @c GTMAppAuthFetcherAuthorizationErrorDomain indicate another + unrecoverable errors. Errors in other domains may indicate a transitive error condition such + as a network error, and typically you do not need to reauthenticate the user on such errors. + @discussion The completion handler is scheduled on the main thread, unless the @c callbackQueue + property is set on the @c fetcherService in which case the handler is scheduled on that + queue. + */ +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + completionHandler:(GTMAppAuthFetcherAuthorizationCompletion)handler; + +/*! @brief Returns YES if the authorization state is currently valid. + @discussion Note that this doesn't guarantee that a request will get a valid authorization, as + the authorization state could become invalid on on the next token refresh. + */ +- (BOOL)canAuthorize; + +@end + +NS_ASSUME_NONNULL_END diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.m b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.m new file mode 100644 index 00000000..988a87b3 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMAppAuthFetcherAuthorization.m @@ -0,0 +1,492 @@ +/*! @file GTMAppAuthFetcherAuthorization.m + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMAppAuthFetcherAuthorization.h" + +#ifndef GTMAPPAUTH_USER_IMPORTS +#import <AppAuth/AppAuthCore.h> +#else // GTMAPPAUTH_USER_IMPORTS +#import "AppAuthCore.h" +#endif // GTMAPPAUTH_USER_IMPORTS + +#define GTMOAuth2AssertValidSelector GTMBridgeAssertValidSelector + +/*! @brief Provides a template implementation for init-family methods which have been marked as + NS_UNAVILABLE. Stops the compiler from giving a warning when it's the super class' + designated initializer, and gives callers useful feedback telling them what the + new designated initializer is. + @remarks Takes a SEL as a parameter instead of a string so that we get compiler warnings if the + designated initializer's signature changes. + @param designatedInitializer A SEL referencing the designated initializer. + */ +#define GTM_UNAVAILABLE_USE_INITIALIZER(designatedInitializer) { \ + NSString *reason = [NSString stringWithFormat:@"Called: %@\nDesignated Initializer:%@", \ + NSStringFromSelector(_cmd), \ + NSStringFromSelector(designatedInitializer)]; \ + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." \ + reason:reason \ + userInfo:nil]; \ +} + +/*! @brief Key used to encode the @c authState property for @c NSSecureCoding. + */ +static NSString *const kAuthStateKey = @"authState"; + +/*! @brief Key used to encode the @c serviceProvider property for @c NSSecureCoding. + */ +static NSString *const kServiceProviderKey = @"serviceProvider"; + +/*! @brief Key used to encode the @c userID property for @c NSSecureCoding. + */ +static NSString *const kUserIDKey = @"userID"; + +/*! @brief Key used to encode the @c userEmail property for @c NSSecureCoding. + */ +static NSString *const kUserEmailKey = @"userEmail"; + +/*! @brief Key used to encode the @c userEmailIsVerified property for @c NSSecureCoding. + */ +static NSString *const kUserEmailIsVerifiedKey = @"userEmailIsVerified"; + +NSString *const GTMAppAuthFetcherAuthorizationErrorDomain = + @"kGTMAppAuthFetcherAuthorizationErrorDomain"; +NSString *const GTMAppAuthFetcherAuthorizationErrorRequestKey = @"request"; + +/*! @brief Internal wrapper class for requests needing authorization and their callbacks. + @discusssion Used to abstract away the detail of whether a callback or block is used. + */ +@interface GTMAppAuthFetcherAuthorizationArgs : NSObject + +/*! @brief The request to authorize. + * @discussion Not copied, as we are mutating the request. + */ +@property (nonatomic, strong) NSMutableURLRequest *request; + +/*! @brief The delegate on which @c selector is called on completion. + */ +@property (nonatomic, weak) id delegate; + +/*! @brief The selector called on the @c delegate object on completion. + */ +@property (nonatomic) SEL selector; + +/*! @brief The completion block when the block option was used. + */ +@property (nonatomic, strong) GTMAppAuthFetcherAuthorizationCompletion completionHandler; + +/*! @brief The error that happened during token refresh (if any). + */ +@property (nonatomic, strong) NSError *error; + ++ (GTMAppAuthFetcherAuthorizationArgs *)argsWithRequest:(NSMutableURLRequest *)req + delegate:(id)delegate + selector:(SEL)selector + completionHandler:(GTMAppAuthFetcherAuthorizationCompletion)completionHandler; + +@end + +@implementation GTMAppAuthFetcherAuthorizationArgs + +@synthesize request = _request; +@synthesize delegate = _delegate; +@synthesize selector = _selector; +@synthesize completionHandler = _completionHandler; +@synthesize error = _error; + ++ (GTMAppAuthFetcherAuthorizationArgs *)argsWithRequest:(NSMutableURLRequest *)req + delegate:(id)delegate + selector:(SEL)selector + completionHandler:(GTMAppAuthFetcherAuthorizationCompletion)completionHandler { + GTMAppAuthFetcherAuthorizationArgs *obj; + obj = [[GTMAppAuthFetcherAuthorizationArgs alloc] init]; + obj.request = req; + obj.delegate = delegate; + obj.selector = selector; + obj.completionHandler = completionHandler; + return obj; +} + +@end + +@implementation GTMAppAuthFetcherAuthorization { + /*! @brief Array of requests pending authorization headers. + */ + NSMutableArray<GTMAppAuthFetcherAuthorizationArgs *> *_authorizationQueue; +} + +@synthesize authState = _authState; +@synthesize serviceProvider = _serviceProvider; +@synthesize userID = _userID; +@synthesize userEmailIsVerified = _userEmailIsVerified; + +// GTMFetcherAuthorizationProtocol doesn't specify atomic/nonatomic for these properties. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wimplicit-atomic-properties" +@synthesize userEmail = _userEmail; +@synthesize shouldAuthorizeAllRequests = _shouldAuthorizeAllRequests; +@synthesize fetcherService = _fetcherService; +#pragma clang diagnostic pop + +#pragma mark - Initializers + +// Ignore warning about not calling the designated initializer. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" +- (instancetype)init + GTM_UNAVAILABLE_USE_INITIALIZER(@selector(initWithAuthState:)); +#pragma clang diagnostic pop + +- (instancetype)initWithAuthState:(OIDAuthState *)authState { + return [self initWithAuthState:authState + serviceProvider:nil + userID:nil + userEmail:nil + userEmailIsVerified:nil]; +} + +- (instancetype)initWithAuthState:(OIDAuthState *)authState + serviceProvider:(nullable NSString *)serviceProvider + userID:(nullable NSString *)userID + userEmail:(nullable NSString *)userEmail + userEmailIsVerified:(nullable NSString *)userEmailIsVerified { + self = [super init]; + if (self) { + _authState = authState; + _authorizationQueue = [[NSMutableArray alloc] init]; + + _serviceProvider = [serviceProvider copy]; + _userID = [userID copy]; + _userEmail = [userEmail copy]; + _userEmailIsVerified = [userEmailIsVerified copy]; + + // Decodes the ID Token locally to extract the email address. + NSString *idToken = _authState.lastTokenResponse.idToken + ? : _authState.lastAuthorizationResponse.idToken; + if (idToken) { + NSDictionary *claimsDictionary = [[OIDIDToken alloc] initWithIDTokenString:idToken].claims; + if (claimsDictionary) { + _userEmail = (NSString *)[claimsDictionary[@"email"] copy]; + _userEmailIsVerified = [(NSNumber *)claimsDictionary[@"email_verified"] stringValue]; + _userID = [claimsDictionary[@"sub"] copy]; + } + } + } + return self; +} + +# pragma mark - Convenience + +#if !GTM_APPAUTH_SKIP_GOOGLE_SUPPORT ++ (OIDServiceConfiguration *)configurationForGoogle { + NSURL *authorizationEndpoint = + [NSURL URLWithString:@"https://accounts.google.com/o/oauth2/v2/auth"]; + NSURL *tokenEndpoint = + [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"]; + + OIDServiceConfiguration *configuration = + [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authorizationEndpoint + tokenEndpoint:tokenEndpoint]; + return configuration; +} +#endif // !GTM_APPAUTH_SKIP_GOOGLE_SUPPORT + +#pragma mark - Authorizing Requests + +/*! @brief Internal routine common to delegate and block invocations to queue requests while + fresh tokens are obtained. + */ +- (void)authorizeRequestArgs:(GTMAppAuthFetcherAuthorizationArgs *)args { + // Adds requests to queue. + @synchronized(_authorizationQueue) { + [_authorizationQueue addObject:args]; + } + + NSDictionary<NSString *, NSString *> *additionalRefreshParameters = _tokenRefreshDelegate ? + [_tokenRefreshDelegate additionalRefreshParameters:self] : nil; + + // Obtains fresh tokens from AppAuth. + [_authState performActionWithFreshTokens:^(NSString *_Nullable accessToken, + NSString *_Nullable idToken, + NSError *_Nullable error) { + // Processes queue. + @synchronized(self->_authorizationQueue) { + for (GTMAppAuthFetcherAuthorizationArgs *fetcherArgs in self->_authorizationQueue) { + [self authorizeRequestImmediateArgs:fetcherArgs accessToken:accessToken error:error]; + } + [self->_authorizationQueue removeAllObjects]; + } + } + additionalRefreshParameters:additionalRefreshParameters]; +} + +/*! @brief Adds authorization headers to the given request, using the supplied access token, or + handles the error. + @param args The request argument group to authorize. + @param accessToken A currently valid access token. + @param error If accessToken is nil, the error which caused the token to be unavailable. + @return YES if the request was authorized with a valid access token. + */ +- (BOOL)authorizeRequestImmediateArgs:(GTMAppAuthFetcherAuthorizationArgs *)args + accessToken:(NSString *)accessToken + error:(NSError *)error { + // This authorization entry point never attempts to refresh the access token, + // but does call the completion routine + + NSMutableURLRequest *request = args.request; + + NSURL *requestURL = [request URL]; + NSString *scheme = [requestURL scheme]; + BOOL isAuthorizableRequest = + !requestURL + || (scheme && [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame) + || [requestURL isFileURL] + || self.shouldAuthorizeAllRequests; + if (!isAuthorizableRequest) { + // Request is not https, a local file, or nil, so may be insecure + // + // The NSError will be created below +#if DEBUG + NSLog(@"Cannot authorize request with scheme %@ (%@)", scheme, request); +#endif + } + + // Get the access token. + if (isAuthorizableRequest && accessToken && accessToken.length > 0) { + if (request) { + // Adds the authorization header to the request. + NSString *value = [NSString stringWithFormat:@"%@ %@", @"Bearer", accessToken]; + [request setValue:value forHTTPHeaderField:@"Authorization"]; + } + + // We've authorized the request, even if the previous refresh + // failed with an error + args.error = nil; + } else { + NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; + if (!userInfo) { + userInfo = [[NSMutableDictionary alloc] init]; + } + if (request) { + userInfo[GTMAppAuthFetcherAuthorizationErrorRequestKey] = request; + } + + if (!isAuthorizableRequest || !error) { + args.error = [NSError errorWithDomain:GTMAppAuthFetcherAuthorizationErrorDomain + code:GTMAppAuthFetcherAuthorizationErrorUnauthorizableRequest + userInfo:userInfo]; + } else { + // Passes through error domain & code from AppAuth, with additional userInfo args. + args.error = [NSError errorWithDomain:error.domain + code:error.code + userInfo:userInfo]; + } + } + + // Invoke any callbacks on the proper thread + if (args.delegate || args.completionHandler) { + // If the fetcher service provides a callback queue, we'll use that + // (or if it's nil, we'll use the main thread) for callbacks. + dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + dispatch_async(callbackQueue, ^{ + [self invokeCallbackArgs:args]; + }); + } + + BOOL didAuth = (args.error == nil); + return didAuth; +} + +/*! @brief Invokes the callback for the given authorization argument group. + @param args The request argument group to invoke following authorization or error. + */ +- (void)invokeCallbackArgs:(GTMAppAuthFetcherAuthorizationArgs *)args { + NSError *error = args.error; + id delegate = args.delegate; + SEL sel = args.selector; + + // If the selector callback method exists, invokes the selector. + if (delegate && sel) { + NSMutableURLRequest *request = args.request; + + NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:sel]; + [invocation setTarget:delegate]; + GTMAppAuthFetcherAuthorization *authorization = self; + [invocation setArgument:&authorization atIndex:2]; + [invocation setArgument:&request atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + + // If a callback block exists, executes the block. + id handler = args.completionHandler; + if (handler) { + void (^authCompletionBlock)(NSError *) = handler; + authCompletionBlock(error); + } +} + +#pragma mark - GTMFetcherAuthorizationProtocol + +/*! @brief Authorizing with a callback selector. + @discussion Selector has the signature: + - (void)authentication:(GTMAppAuthFetcherAuthorization *)auth + request:(NSMutableURLRequest *)request + finishedWithError:(NSError *)error; + */ +- (void)authorizeRequest:(NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel { + GTMOAuth2AssertValidSelector(delegate, sel, + @encode(GTMAppAuthFetcherAuthorization *), + @encode(NSMutableURLRequest *), + @encode(NSError *), 0); + + GTMAppAuthFetcherAuthorizationArgs *args; + args = [GTMAppAuthFetcherAuthorizationArgs argsWithRequest:request + delegate:delegate + selector:sel + completionHandler:nil]; + [self authorizeRequestArgs:args]; +} + +/*! @brief Removes all pending requests from the authorization queue. + */ +- (void)stopAuthorization { + @synchronized(_authorizationQueue) { + [_authorizationQueue removeAllObjects]; + } +} + +/*! @brief Attempts to remove a specific pending requests from the authorization queue. + @discussion Has no effect if the authorization already occurred. + */ +- (void)stopAuthorizationForRequest:(NSURLRequest *)request { + @synchronized(_authorizationQueue) { + NSUInteger argIndex = 0; + BOOL found = NO; + for (GTMAppAuthFetcherAuthorizationArgs *args in _authorizationQueue) { + // Checks pointer equality with given request, don't want to match equivalent requests. + if ([args request] == request) { + found = YES; + break; + } + argIndex++; + } + + if (found) { + [_authorizationQueue removeObjectAtIndex:argIndex]; + + // If the queue is now empty, go ahead and stop the fetcher. + if (_authorizationQueue.count == 0) { + [self stopAuthorization]; + } + } + } +} + +/*! @brief Returns YES if the given requests is in the pending authorization queue. + */ +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request { + BOOL wasFound = NO; + @synchronized(_authorizationQueue) { + for (GTMAppAuthFetcherAuthorizationArgs *args in _authorizationQueue) { + // Checks pointer equality with given request, don't want to match equivalent requests. + if ([args request] == request) { + wasFound = YES; + break; + } + } + } + return wasFound; +} + +/*! @brief Returns YES if given request has an Authorization header. + */ +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request { + NSString *authStr = [request valueForHTTPHeaderField:@"Authorization"]; + return (authStr.length > 0); +} + +/*! @brief Returns YES if the authorization state is currently valid. + @discussion Note that the state can become invalid immediately due to an error on token refresh. + */ +- (BOOL)canAuthorize { + return [_authState isAuthorized]; +} + +/*! @brief Authorizing with a completion block. + */ +- (void)authorizeRequest:(NSMutableURLRequest *)request + completionHandler:(GTMAppAuthFetcherAuthorizationCompletion)handler { + GTMAppAuthFetcherAuthorizationArgs *args = + [GTMAppAuthFetcherAuthorizationArgs argsWithRequest:request + delegate:nil + selector:NULL + completionHandler:handler]; + [self authorizeRequestArgs:args]; +} + +/*! @brief Forces a token refresh the next time a request is queued for authorization. + */ +- (BOOL)primeForRefresh { + if (_authState.refreshToken == nil) { + // Cannot refresh without a refresh token + return NO; + } + [_authState setNeedsTokenRefresh]; + return YES; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + OIDAuthState *authState = + [aDecoder decodeObjectOfClass:[OIDAuthState class] forKey:kAuthStateKey]; + NSString *serviceProvider = + [aDecoder decodeObjectOfClass:[NSString class] forKey:kServiceProviderKey]; + NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDKey]; + NSString *userEmail = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserEmailKey]; + NSString *userEmailIsVerified = + [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserEmailIsVerifiedKey]; + + self = [self initWithAuthState:authState + serviceProvider:serviceProvider + userID:userID + userEmail:userEmail + userEmailIsVerified:userEmailIsVerified]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_authState forKey:kAuthStateKey]; + [aCoder encodeObject:_serviceProvider forKey:kServiceProviderKey]; + [aCoder encodeObject:_userID forKey:kUserIDKey]; + [aCoder encodeObject:_userEmail forKey:kUserEmailKey]; + [aCoder encodeObject:_userEmailIsVerified forKey:kUserEmailIsVerifiedKey]; +} + +@end diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMKeychain.h b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMKeychain.h new file mode 100644 index 00000000..b4d5d062 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMKeychain.h @@ -0,0 +1,62 @@ +/*! @file GTMKeychain.h + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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> + +NS_ASSUME_NONNULL_BEGIN + +/*! @brief Utility for saving and loading data to the keychain. + */ +@interface GTMKeychain : NSObject + +/*! @brief Saves the password string to the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @param password Password string to save. + @return YES when the password string was saved successfully. + */ ++ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName password:(NSString *)password; + +/*! @brief Loads the password string from the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @return The password string at the given identifier, or nil. + */ ++ (nullable NSString *)passwordFromKeychainForName:(NSString *)keychainItemName; + +/*! @brief Saves the password data to the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @param passwordData Password data to save. + @return YES when the password data was saved successfully. + */ ++ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName + passwordData:(NSData *)passwordData; + +/*! @brief Loads the password data from the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @return The password data at the given identifier, or nil. + */ ++ (nullable NSData *)passwordDataFromKeychainForName:(NSString *)keychainItemName; + +/*! @brief Removes stored password string, such as when the user signs out. + @param keychainItemName Keychain name of the item. + @return YES if the password string was removed successfully (or didn't exist). + */ ++ (BOOL)removePasswordFromKeychainForName:(NSString *)keychainItemName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.h b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.h new file mode 100644 index 00000000..9c0c5bf1 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.h @@ -0,0 +1,131 @@ +/*! @file GTMOAuth2Compatibility.h + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMAppAuthFetcherAuthorization.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! @brief Class to support serialization and deserialization of @c GTMAppAuthFetcherAuthorization + in the format used by GTMOAuth2. + @discussion The methods of this class are capable of serializing and deserializing auth + objects in a way compatible with the serialization in @c GTMOAuth2ViewControllerTouch and + @c GTMOAuth2WindowController in GTMOAuth2. + */ +@interface GTMOAuth2KeychainCompatibility : NSObject + +/*! @brief Encodes the given @c GTMAppAuthFetcherAuthorization in a GTMOAuth2 compatible persistence + string using URL param key/value encoding. + @param authorization The @c GTMAppAuthFetcherAuthorization to serialize in GTMOAuth2 format. + @return The GTMOAuth2 persistence representation of this object. + */ ++ (NSString *)persistenceResponseStringForAuthorization: + (GTMAppAuthFetcherAuthorization *)authorization; + +/*! @brief Attempts to create a @c GTMAppAuthFetcherAuthorization from data stored in the keychain + in GTMOAuth2 format, at the supplied keychain identifier. + @param keychainItemName The keychain name. + @param tokenURL The OAuth token endpoint URL. + @param redirectURI The OAuth redirect URI used when obtaining the original authorization. + @param clientID The OAuth client id. + @param clientSecret The OAuth client secret. + @return A @c GTMAppAuthFetcherAuthorization object, or nil. + */ ++ (nullable GTMAppAuthFetcherAuthorization *) + authorizeFromKeychainForName:(NSString *)keychainItemName + tokenURL:(NSURL *)tokenURL + redirectURI:(NSString *)redirectURI + clientID:(NSString *)clientID + clientSecret:(nullable NSString *)clientSecret; + +/*! @brief Attempts to create a @c GTMAppAuthFetcherAuthorization from a @c NSString + representation of the GTMOAuth2 keychain data. + @param persistenceString String representation of the GTMOAuth2 keychain data. + @param tokenURL The OAuth token endpoint URL. + @param redirectURI The OAuth redirect URI used when obtaining the original authorization. + @param clientID The OAuth client id. + @param clientSecret The OAuth client secret. + @return A @c GTMAppAuthFetcherAuthorization object, or nil. + */ ++ (nullable GTMAppAuthFetcherAuthorization *) + authorizeFromPersistenceString:(NSString *)persistenceString + tokenURL:(NSURL *)tokenURL + redirectURI:(NSString *)redirectURI + clientID:(NSString *)clientID + clientSecret:(nullable NSString *)clientSecret; + +/*! @brief Removes stored tokens, such as when the user signs out. + @param keychainItemName The keychain name. + @return YES the tokens were removed successfully (or didn't exist). + */ ++ (BOOL)removeAuthFromKeychainForName:(NSString *)keychainItemName; + +/*! @brief Saves the authorization state to the keychain, in a GTMOAuth2 compatible manner. + @param keychainItemName The keychain name. + @return YES when the state was saved successfully. + */ ++ (BOOL)saveAuthToKeychainForName:(NSString *)keychainItemName + authentication:(GTMAppAuthFetcherAuthorization *)auth + __attribute__((deprecated( + "Use GTMAppAuthFetcherAuthorization::saveAuthorization:toKeychainForName:"))); + +#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + +/*! @brief Attempts to create a @c GTMAppAuthFetcherAuthorization from data stored in the keychain + in GTMOAuth2 format, at the supplied keychain identifier. Uses Google OAuth provider + information. + @param keychainItemName The keychain name. + @param clientID The OAuth client id. + @param clientSecret The OAuth client secret. + @return A @c GTMAppAuthFetcherAuthorization object, or nil. + */ ++ (nullable GTMAppAuthFetcherAuthorization *) + authForGoogleFromKeychainForName:(NSString *)keychainItemName + clientID:(NSString *)clientID + clientSecret:(nullable NSString *)clientSecret; + +/*! @brief Returns Google's OAuth 2.0 authorization endpoint. + @return Returns Google's OAuth 2.0 authorization endpoint. + */ ++ (NSURL *)googleAuthorizationURL; + +/*! @brief Returns Google's OAuth 2.0 token endpoint. + @return Returns Google's OAuth 2.0 token endpoint. + */ ++ (NSURL *)googleTokenURL; + +/*! @brief Returns Google's OAuth 2.0 revocation endpoint. + @return Returns Google's OAuth 2.0 revocation endpoint. + */ ++ (NSURL *)googleRevocationURL; + +/*! @brief Returns Google's OAuth 2.0 userinfo endpoint. + @return Returns Google's OAuth 2.0 userinfo endpoint. + */ ++ (NSURL *)googleUserInfoURL; + +/*! @brief Returns Google's native OOB redirect URI. + @discussion This is a legacy redirect URI that was used with WebViews. + @return Returns Google's native OOB redirect URI. + */ ++ (NSString *)nativeClientRedirectURI; + +#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + +@end + +NS_ASSUME_NONNULL_END diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.m b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.m new file mode 100644 index 00000000..5e56341b --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/GTMOAuth2KeychainCompatibility/GTMOAuth2KeychainCompatibility.m @@ -0,0 +1,325 @@ +/*! @file GTMOAuth2Compatibility.m + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMOAuth2KeychainCompatibility.h" + +#ifndef GTMAPPAUTH_USER_IMPORTS +#import <AppAuth/AppAuthCore.h> +#else // GTMAPPAUTH_USER_IMPORTS +#import "AppAuthCore.h" +#endif // GTMAPPAUTH_USER_IMPORTS + +#import "GTMKeychain.h" + +// standard OAuth keys +static NSString *const kOAuth2AccessTokenKey = @"access_token"; +static NSString *const kOAuth2RefreshTokenKey = @"refresh_token"; +static NSString *const kOAuth2ScopeKey = @"scope"; +static NSString *const kOAuth2ErrorKey = @"error"; +static NSString *const kOAuth2TokenTypeKey = @"token_type"; +static NSString *const kOAuth2ExpiresInKey = @"expires_in"; +static NSString *const kOAuth2CodeKey = @"code"; +static NSString *const kOAuth2AssertionKey = @"assertion"; +static NSString *const kOAuth2RefreshScopeKey = @"refreshScope"; + +// additional persistent keys +static NSString *const kServiceProviderKey = @"serviceProvider"; +static NSString *const kUserIDKey = @"userID"; +static NSString *const kUserEmailKey = @"email"; +static NSString *const kUserEmailIsVerifiedKey = @"isVerified"; + +// URI indicating an installed app is signing in. This is described at +// +// https://developers.google.com/identity/protocols/OAuth2InstalledApp#formingtheurl +// +static NSString *const kOOBString = @"urn:ietf:wg:oauth:2.0:oob"; + +@implementation GTMOAuth2KeychainCompatibility + +// This returns a "response string" that can be passed later to +// setKeysForResponseString: to reuse an old access token in a new auth object ++ (NSString *)persistenceResponseStringForAuthorization: + (GTMAppAuthFetcherAuthorization *)authorization { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + + NSString *refreshToken = authorization.authState.refreshToken; + NSString *accessToken = authorization.authState.lastTokenResponse.accessToken; + + // Any nil values will not set a dictionary entry + [dict setValue:refreshToken forKey:kOAuth2RefreshTokenKey]; + [dict setValue:accessToken forKey:kOAuth2AccessTokenKey]; + [dict setValue:authorization.serviceProvider forKey:kServiceProviderKey]; + [dict setValue:authorization.userID forKey:kUserIDKey]; + [dict setValue:authorization.userEmail forKey:kUserEmailKey]; + [dict setValue:authorization.userEmailIsVerified forKey:kUserEmailIsVerifiedKey]; + [dict setValue:authorization.authState.scope forKey:kOAuth2ScopeKey]; + + NSString *result = [self encodedQueryParametersForDictionary:dict]; + return result; +} + ++ (GTMAppAuthFetcherAuthorization *)authorizeFromKeychainForName:(NSString *)keychainItemName + tokenURL:(NSURL *)tokenURL + redirectURI:(NSString *)redirectURI + clientID:(NSString *)clientID + clientSecret:(nullable NSString *)clientSecret { + // Loads password string from keychain. + NSString *password = [GTMKeychain passwordFromKeychainForName:keychainItemName]; + + if (!password) { + return nil; + } + + GTMAppAuthFetcherAuthorization *authorization = + [self authorizeFromPersistenceString:password + tokenURL:tokenURL + redirectURI:redirectURI + clientID:clientID + clientSecret:clientSecret]; + return authorization; +} + ++ (GTMAppAuthFetcherAuthorization *)authorizeFromPersistenceString:(NSString *)persistenceString + tokenURL:(NSURL *)tokenURL + redirectURI:(NSString *)redirectURIString + clientID:(NSString *)clientID + clientSecret:(NSString *)clientSecret { + // Parses persistence data into NSDictionary. + NSDictionary *dict = [self dictionaryWithResponseString:persistenceString]; + + NSURL *redirectURI = (NSURL *)[NSURL URLWithString:redirectURIString]; + + // OIDAuthState is based on the request/response history. + // Creates history based on the data from the keychain, and client details passed in. + OIDServiceConfiguration *authConfig = + [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:tokenURL tokenEndpoint:tokenURL]; + OIDAuthorizationRequest *authRequest = + [[OIDAuthorizationRequest alloc] initWithConfiguration:authConfig + clientId:clientID + clientSecret:clientSecret + scope:dict[kOAuth2ScopeKey] + redirectURL:redirectURI + responseType:OIDResponseTypeCode + state:nil + nonce:nil + codeVerifier:nil + codeChallenge:nil + codeChallengeMethod:nil + additionalParameters:nil]; + OIDAuthorizationResponse *authResponse = + [[OIDAuthorizationResponse alloc] initWithRequest:authRequest parameters:dict]; + // Exclude scope and refresh token parameters from additionalParameters. + NSMutableDictionary *additionalParameters = [dict mutableCopy]; + [additionalParameters removeObjectForKey:kOAuth2ScopeKey]; + [additionalParameters removeObjectForKey:kOAuth2RefreshTokenKey]; + OIDTokenRequest *tokenRequest = + [[OIDTokenRequest alloc] initWithConfiguration:authConfig + grantType:@"token" + authorizationCode:nil + redirectURL:redirectURI + clientID:clientID + clientSecret:clientSecret + scope:dict[kOAuth2ScopeKey] + refreshToken:dict[kOAuth2RefreshTokenKey] + codeVerifier:nil + additionalParameters:additionalParameters]; + OIDTokenResponse *tokenResponse = + [[OIDTokenResponse alloc] initWithRequest:tokenRequest parameters:dict]; + OIDAuthState *authState = [[OIDAuthState alloc] initWithAuthorizationResponse:authResponse + tokenResponse:tokenResponse]; + // We're not serializing the token expiry date, so the first refresh needs to be forced. + [authState setNeedsTokenRefresh]; + + GTMAppAuthFetcherAuthorization *authorizer = + [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState + serviceProvider:dict[kServiceProviderKey] + userID:dict[kUserIDKey] + userEmail:dict[kUserEmailKey] + userEmailIsVerified:dict[kUserEmailIsVerifiedKey]]; + return authorizer; +} + +#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + ++ (GTMAppAuthFetcherAuthorization *)authForGoogleFromKeychainForName:(NSString *)keychainItemName + clientID:(NSString *)clientID + clientSecret:(NSString *)clientSecret { + Class signInClass = self; + NSURL *tokenURL = [signInClass googleTokenURL]; + NSString *redirectURI = [signInClass nativeClientRedirectURI]; + + GTMAppAuthFetcherAuthorization *auth; + auth = [self authorizeFromKeychainForName:keychainItemName + tokenURL:tokenURL + redirectURI:redirectURI + clientID:clientID + clientSecret:clientSecret]; + return auth; +} + +#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + +/*! @brief Removes stored tokens, such as when the user signs out. + @return YES the tokens were removed successfully (or didn't exist). + */ ++ (BOOL)removeAuthFromKeychainForName:(NSString *)keychainItemName { + return [GTMKeychain removePasswordFromKeychainForName:keychainItemName]; +} + +/*! @brief Saves the authorization state to the keychain, in a GTMOAuth2 compatible manner. + @return YES when the state was saved successfully. + */ ++ (BOOL)saveAuthToKeychainForName:(NSString *)keychainItemName + authentication:(GTMAppAuthFetcherAuthorization *)auth { + [self removeAuthFromKeychainForName:keychainItemName]; + NSString *password = [self persistenceResponseStringForAuthorization:auth]; + + return [GTMKeychain savePasswordToKeychainForName:keychainItemName password:password]; +} + +#pragma mark Utility Routines + ++ (NSString *)encodedQueryParametersForDictionary:(NSDictionary *)dict { + // Make a string like "cat=fluffy&dog=spot" + NSMutableString *result = [NSMutableString string]; + NSArray *sortedKeys = + [[dict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; + NSString *joiner = @""; + for (NSString *key in sortedKeys) { + NSString *value = [dict objectForKey:key]; + NSString *encodedValue = [self encodedOAuthValueForString:value]; + NSString *encodedKey = [self encodedOAuthValueForString:key]; + [result appendFormat:@"%@%@=%@", joiner, encodedKey, encodedValue]; + joiner = @"&"; + } + return result; +} + ++ (NSString *)encodedOAuthValueForString:(NSString *)originalString { + // For parameters, we'll explicitly leave spaces unescaped now, and replace + // them with +'s + NSString *const kForceEscape = @"!*'();:@&=+$,/?%#[]"; + +#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9) \ + || (TARGET_OS_IPHONE && defined(__IPHONE_7_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) + // Builds targeting iOS 7/OS X 10.9 and higher only. + NSMutableCharacterSet *cs = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; + [cs removeCharactersInString:kForceEscape]; + + return [originalString stringByAddingPercentEncodingWithAllowedCharacters:cs]; +#else + // Builds targeting iOS 6/OS X 10.8. + CFStringRef escapedStr = NULL; + if (originalString) { + escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)originalString, + NULL, + (CFStringRef)kForceEscape, + kCFStringEncodingUTF8); + } + + return (__bridge NSString *)escapedStr; +#endif +} + ++ (NSDictionary *)dictionaryWithResponseString:(NSString *)responseStr { + // Build a dictionary from a response string of the form + // "cat=fluffy&dog=spot". Missing or empty values are considered + // empty strings; keys and values are percent-decoded. + if (responseStr == nil) return nil; + + NSArray *items = [responseStr componentsSeparatedByString:@"&"]; + + NSMutableDictionary *responseDict = [NSMutableDictionary dictionaryWithCapacity:items.count]; + + for (NSString *item in items) { + NSString *key; + NSString *value = @""; + + NSRange equalsRange = [item rangeOfString:@"="]; + if (equalsRange.location != NSNotFound) { + // The parameter has at least one '=' + key = [item substringToIndex:equalsRange.location]; + + // There are characters after the '=' + if (equalsRange.location + 1 < item.length) { + value = [item substringFromIndex:(equalsRange.location + 1)]; + } + } else { + // The parameter has no '=' + key = item; + } + + NSString *plainKey = [self unencodedOAuthParameterForString:key]; + NSString *plainValue = [self unencodedOAuthParameterForString:value]; + + [responseDict setObject:plainValue forKey:plainKey]; + } + + return responseDict; +} + ++ (NSString *)unencodedOAuthParameterForString:(NSString *)str { +#if (!TARGET_OS_IPHONE \ + && defined(MAC_OS_X_VERSION_10_9) \ + && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9) \ + || (TARGET_OS_IPHONE \ + && defined(__IPHONE_7_0) \ + && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) + // On iOS 7, -stringByRemovingPercentEncoding incorrectly returns nil for an empty string. + if (str != nil && [str length] == 0) return @""; + + NSString *plainStr = [str stringByRemovingPercentEncoding]; + return plainStr; +#else + NSString *plainStr = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + return plainStr; +#endif +} + +#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + +// Endpoint URLs are available at https://accounts.google.com/.well-known/openid-configuration + ++ (NSURL *)googleAuthorizationURL { + NSString *str = @"https://accounts.google.com/o/oauth2/v2/auth"; + return (NSURL *)[NSURL URLWithString:str]; +} + ++ (NSURL *)googleTokenURL { + NSString *str = @"https://www.googleapis.com/oauth2/v4/token"; + return (NSURL *)[NSURL URLWithString:str]; +} + ++ (NSURL *)googleRevocationURL { + NSString *urlStr = @"https://accounts.google.com/o/oauth2/revoke"; + return (NSURL *)[NSURL URLWithString:urlStr]; +} + ++ (NSURL *)googleUserInfoURL { + NSString *urlStr = @"https://www.googleapis.com/oauth2/v3/userinfo"; + return (NSURL *)[NSURL URLWithString:urlStr]; +} + ++ (NSString *)nativeClientRedirectURI { + return kOOBString; +} + +#endif // !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT + +@end diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/iOS/GTMKeychain_iOS.m b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/iOS/GTMKeychain_iOS.m new file mode 100644 index 00000000..ab64882e --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/Source/iOS/GTMKeychain_iOS.m @@ -0,0 +1,287 @@ +/*! @file GTMKeychain_iOS.m + @brief GTMAppAuth SDK + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "GTMKeychain.h" + +#import <Security/Security.h> + +typedef NS_ENUM(NSInteger, GTMAppAuthFetcherAuthorizationGTMAppAuthGTMOAuth2KeychainError) { + GTMAppAuthGTMOAuth2KeychainErrorBadArguments = -1301, + GTMAppAuthGTMOAuth2KeychainErrorNoPassword = -1302 +}; + +/*! @brief Keychain helper class. + */ +@interface GTMAppAuthGTMOAuth2Keychain : NSObject + ++ (GTMAppAuthGTMOAuth2Keychain *)defaultKeychain; + +// OK to pass nil for the error parameter. +- (NSString *)passwordForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error; + +- (NSData *)passwordDataForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error; + +// OK to pass nil for the error parameter. +- (BOOL)removePasswordForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error; + +// OK to pass nil for the error parameter. +// +// accessibility should be one of the constants for kSecAttrAccessible +// such as kSecAttrAccessibleWhenUnlocked +- (BOOL)setPassword:(NSString *)password + forService:(NSString *)service + accessibility:(CFTypeRef)accessibility + account:(NSString *)account + error:(NSError **)error; + +- (BOOL)setPasswordData:(NSData *)passwordData + forService:(NSString *)service + accessibility:(CFTypeRef)accessibility + account:(NSString *)account + error:(NSError **)error; + +// For unit tests: allow setting a mock object ++ (void)setDefaultKeychain:(GTMAppAuthGTMOAuth2Keychain *)keychain; + +@end + +NSString *const kGTMAppAuthFetcherAuthorizationGTMOAuth2ErrorDomain = @"com.google.GTMOAuth2"; +NSString *const kGTMAppAuthFetcherAuthorizationGTMOAuth2KeychainErrorDomain = + @"com.google.GTMOAuthKeychain"; +static NSString *const kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName = @"OAuth"; +static GTMAppAuthGTMOAuth2Keychain* gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain = nil; + +@implementation GTMKeychain + ++ (BOOL)removePasswordFromKeychainForName:(NSString *)keychainItemName { + GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain]; + return [keychain removePasswordForService:keychainItemName + account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName + error:nil]; +} + ++ (NSString *)passwordFromKeychainForName:(NSString *)keychainItemName { + GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain]; + NSError *error; + NSString *password = + [keychain passwordForService:keychainItemName + account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName + error:&error]; + return password; +} + ++ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName password:(NSString *)password { + return [self savePasswordToKeychainForName:keychainItemName + password:password + accessibility:NULL + error:NULL]; +} + ++ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName password:(NSString *)password + accessibility:(CFTypeRef)accessibility + error:(NSError **)error { + if (accessibility == NULL) { + accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } + // make a response string containing the values we want to save + GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain]; + return [keychain setPassword:password + forService:keychainItemName + accessibility:accessibility + account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName + error:error]; +} + +/*! @brief Saves the password string to the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @param password Password string to save. + @return YES when the password string was saved successfully. + */ ++ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName + passwordData:(NSData *)password { + CFTypeRef accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + // make a response string containing the values we want to save + GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain]; + return [keychain setPasswordData:password + forService:keychainItemName + accessibility:accessibility + account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName + error:NULL]; +} + +/*! @brief Loads the password string from the keychain with the given identifier. + @param keychainItemName Keychain name of the item. + @return The password string at the given identifier, or nil. + */ ++ (NSData *)passwordDataFromKeychainForName:(NSString *)keychainItemName { + GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain]; + NSError *error; + NSData *password = + [keychain passwordDataForService:keychainItemName + account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName + error:&error]; + return password; +} + +@end + +#pragma mark GTMAppAuthGTMOAuth2Keychain + +@implementation GTMAppAuthGTMOAuth2Keychain + ++ (GTMAppAuthGTMOAuth2Keychain *)defaultKeychain { + static dispatch_once_t onceToken; + dispatch_once (&onceToken, ^{ + gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain = [[self alloc] init]; + }); + return gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain; +} + + +// For unit tests: allow setting a mock object ++ (void)setDefaultKeychain:(GTMAppAuthGTMOAuth2Keychain *)keychain { + if (gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain != keychain) { + gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain = keychain; + } +} + +- (NSString *)keyForService:(NSString *)service account:(NSString *)account { + return [NSString stringWithFormat:@"com.google.GTMOAuth.%@%@", service, account]; +} + ++ (NSMutableDictionary *)keychainQueryForService:(NSString *)service account:(NSString *)account { + NSMutableDictionary *query = + [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword, (id)kSecClass, + @"OAuth", (id)kSecAttrGeneric, + account, (id)kSecAttrAccount, + service, (id)kSecAttrService, + nil]; + return query; +} + +- (NSMutableDictionary *)keychainQueryForService:(NSString *)service account:(NSString *)account { + return [[self class] keychainQueryForService:service account:account]; +} + +// iPhone +- (NSString *)passwordForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error { + NSData *passwordData = [self passwordDataForService:service account:account error:error]; + if (!passwordData) { + return nil; + } + NSString *result = [[NSString alloc] initWithData:passwordData + encoding:NSUTF8StringEncoding]; + return result; +} + +// iPhone +- (NSData *)passwordDataForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error { + OSStatus status = GTMAppAuthGTMOAuth2KeychainErrorBadArguments; + NSData *result = nil; + if (service.length > 0 && account.length > 0) { + CFDataRef passwordData = NULL; + NSMutableDictionary *keychainQuery = [self keychainQueryForService:service account:account]; + [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; + [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; + + status = SecItemCopyMatching((CFDictionaryRef)keychainQuery, + (CFTypeRef *)&passwordData); + if (status == noErr && 0 < [(__bridge NSData *)passwordData length]) { + result = [(__bridge NSData *)passwordData copy]; + } + if (passwordData != NULL) { + CFRelease(passwordData); + } + } + if (status != noErr && error != NULL) { + *error = [NSError errorWithDomain:kGTMAppAuthFetcherAuthorizationGTMOAuth2KeychainErrorDomain + code:status + userInfo:nil]; + } + return result; +} + +// iPhone +- (BOOL)removePasswordForService:(NSString *)service + account:(NSString *)account + error:(NSError **)error { + OSStatus status = GTMAppAuthGTMOAuth2KeychainErrorBadArguments; + if (0 < [service length] && 0 < [account length]) { + NSMutableDictionary *keychainQuery = [self keychainQueryForService:service account:account]; + status = SecItemDelete((CFDictionaryRef)keychainQuery); + } + if (status != noErr && error != NULL) { + *error = [NSError errorWithDomain:kGTMAppAuthFetcherAuthorizationGTMOAuth2KeychainErrorDomain + code:status + userInfo:nil]; + } + return status == noErr; +} + +// iPhone +- (BOOL)setPassword:(NSString *)password + forService:(NSString *)service + accessibility:(CFTypeRef)accessibility + account:(NSString *)account + error:(NSError **)error { + NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; + return [self setPasswordData:passwordData + forService:service + accessibility:accessibility + account:account + error:error]; +} + +- (BOOL)setPasswordData:(NSData *)passwordData + forService:(NSString *)service + accessibility:(CFTypeRef)accessibility + account:(NSString *)account + error:(NSError **)error { + OSStatus status = GTMAppAuthGTMOAuth2KeychainErrorBadArguments; + if (0 < [service length] && 0 < [account length]) { + [self removePasswordForService:service account:account error:nil]; + if (0 < [passwordData length]) { + NSMutableDictionary *keychainQuery = [self keychainQueryForService:service account:account]; + [keychainQuery setObject:passwordData forKey:(id)kSecValueData]; + + if (accessibility != NULL) { + [keychainQuery setObject:(__bridge id)accessibility + forKey:(id)kSecAttrAccessible]; + } + status = SecItemAdd((CFDictionaryRef)keychainQuery, NULL); + } + } + if (status != noErr && error != NULL) { + *error = [NSError errorWithDomain:kGTMAppAuthFetcherAuthorizationGTMOAuth2KeychainErrorDomain + code:status + userInfo:nil]; + } + return status == noErr; +} + +@end |
