diff options
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/GTMAppAuth')
11 files changed, 2165 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/LICENSE b/StoneIsland/platforms/ios/Pods/GTMAppAuth/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/StoneIsland/platforms/ios/Pods/GTMAppAuth/README.md b/StoneIsland/platforms/ios/Pods/GTMAppAuth/README.md new file mode 100644 index 00000000..e2c02fd0 --- /dev/null +++ b/StoneIsland/platforms/ios/Pods/GTMAppAuth/README.md @@ -0,0 +1,385 @@ +# GTMAppAuth for iOS and macOS + +GTMAppAuth enables you to use [AppAuth](http://openid.github.io/AppAuth-iOS) +with the +[Google Toolbox for Mac - Session Fetcher](https://github.com/google/gtm-session-fetcher) +and +[Google APIs Client Library for Objective-C For REST](https://github.com/google/google-api-objectivec-client-for-rest) +libraries by providing an implementation of `GTMFetcherAuthorizationProtocol` +for authorizing requests with AppAuth. + +GTMAppAuth is an alternative authorizer to GTMOAuth2. The key differentiator is +the use of the user's default browser for the authorization, which is more +secure, more usable (the user's session can be reused) and follows modern OAuth +[best practices for native apps](https://tools.ietf.org/html/draft-ietf-oauth-native-apps). +Compatibility methods for GTMOAuth2 are offered allowing you to migrate +from GTMOAuth2 to GTMAppAuth preserving previously serialized authorizations +(so users shouldn't need to re-authenticate). + +## Setup + +If you use [CocoaPods](https://guides.cocoapods.org/using/getting-started.html), +simply add: + + pod 'GTMAppAuth' + +To your `Podfile` and run `pod install`. + +## Usage + +### Configuration + +To configure GTMAppAuth with the OAuth endpoints for Google, you can use the +convenience method: + +```objc +OIDServiceConfiguration *configuration = + [GTMAppAuthFetcherAuthorization configurationForGoogle]; +``` + +Alternatively, you can configure GTMAppAuth by specifying the endpoints +directly: + +```objc +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]; + +// perform the auth request... +``` + +Or through discovery: + +```objc +NSURL *issuer = [NSURL URLWithString:@"https://accounts.google.com"]; + +[OIDAuthorizationService discoverServiceConfigurationForIssuer:issuer + completion:^(OIDServiceConfiguration *_Nullable configuration, + NSError *_Nullable error) { + if (!configuration) { + NSLog(@"Error retrieving discovery document: %@", + [error localizedDescription]); + return; + } + + // perform the auth request... +}]; +``` + +### Authorizing + +First, you need to have a way for your UIApplicationDelegate to continue the +authorization flow session from the incoming redirect URI. Typically you could +store the in-progress OIDAuthorizationFlowSession instance in a property: + +```objc +// property of the app's UIApplicationDelegate +@property(nonatomic, nullable) + id<OIDExternalUserAgentSession> currentAuthorizationFlow; +``` + +And in a location accessible by all controllers that need authorization, a +property to store the authorization state: + +```objc +// property of the containing class +@property(nonatomic, nullable) GTMAppAuthFetcherAuthorization *authorization; +``` + +Then, initiate the authorization request. By using the +`authStateByPresentingAuthorizationRequest` method, the OAuth token +exchange will be performed automatically, and everything will be protected with +PKCE (if the server supports it). + +```objc +// builds authentication request +OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration + clientId:kClientID + clientSecret:kClientSecret + scopes:@[OIDScopeOpenID, OIDScopeProfile] + redirectURL:redirectURI + responseType:OIDResponseTypeCode + additionalParameters:nil]; +// performs authentication request +self.appDelegate.currentAuthorizationFlow = + [OIDAuthState authStateByPresentingAuthorizationRequest:request + callback:^(OIDAuthState *_Nullable authState, + NSError *_Nullable error) { + if (authState) { + // Creates the GTMAppAuthFetcherAuthorization from the OIDAuthState. + GTMAppAuthFetcherAuthorization *authorization = + [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState]; + + self.authorization = authorization; + NSLog(@"Got authorization tokens. Access token: %@", + authState.lastTokenResponse.accessToken); + } else { + NSLog(@"Authorization error: %@", [error localizedDescription]); + self.authorization = nil; + } +}]; +``` + +### Handling the Redirect + +The authorization response URL is returned to the app via the platform-specific +application delegate method, so you need to pipe this through to the current +authorization session (created in the previous session). + +#### macOS Custom URI Scheme Redirect Example + +```objc +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Other app initialization code ... + + // Register for GetURL events. + NSAppleEventManager *appleEventManager = + [NSAppleEventManager sharedAppleEventManager]; + [appleEventManager setEventHandler:self + andSelector:@selector(handleGetURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; +} + +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event + withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + NSString *URLString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + NSURL *URL = [NSURL URLWithString:URLString]; + [_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:URL]; +} +``` + +#### iOS Custom URI Scheme Redirect Example + +```objc +- (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary<NSString *, id> *)options { + // Sends the URL to the current authorization flow (if any) which will + // process it if it relates to an authorization response. + if ([_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url]) { + _currentAuthorizationFlow = nil; + return YES; + } + + // Your additional URL handling (if any) goes here. + + return NO; +} +``` + +### Making API Calls + +The goal of GTMAppAuth is to enable you to authorize HTTP requests with fresh +tokens following the Session Fetcher pattern, which you can do like so: + +```objc +// Creates a GTMSessionFetcherService with the authorization. +// Normally you would save this service object and re-use it for all REST API calls. +GTMSessionFetcherService *fetcherService = [[GTMSessionFetcherService alloc] init]; +fetcherService.authorizer = self.authorization; + +// Creates a fetcher for the API call. +NSURL *userinfoEndpoint = [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v3/userinfo"]; +GTMSessionFetcher *fetcher = [fetcherService fetcherWithURL:userinfoEndpoint]; +[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + // Checks for an error. + if (error) { + // OIDOAuthTokenErrorDomain indicates an issue with the authorization. + if ([error.domain isEqual:OIDOAuthTokenErrorDomain]) { + self.authorization = nil; + NSLog(@"Authorization error during token refresh, clearing state. %@", + error); + // Other errors are assumed transient. + } else { + NSLog(@"Transient error during token refresh. %@", error); + } + return; + } + + // Parses the JSON response. + NSError *jsonError = nil; + id jsonDictionaryOrArray = + [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; + + // JSON error. + if (jsonError) { + NSLog(@"JSON decoding error %@", jsonError); + return; + } + + // Success response! + NSLog(@"Success: %@", jsonDictionaryOrArray); +}]; +``` + +### Serialization + +You can easily serialize `GTMAppAuthFetcherAuthorization` objects using the +included Keychain category. + +```objc +// Serialize to Keychain +[GTMAppAuthFetcherAuthorization saveAuthorization:_authorization + toKeychainForName:kGTMAppAuthExampleAuthorizerKey]; + +// Deserialize from Keychain +GTMAppAuthFetcherAuthorization* authorization = + [GTMAppAuthFetcherAuthorization authorizationFromKeychainForName:kGTMAppAuthExampleAuthorizerKey]; + +// Remove from Keychain +[GTMAppAuthFetcherAuthorization + removeAuthorizationFromKeychainForName:kGTMAppAuthExampleAuthorizerKey]; +``` + +### GTMOAuth2-compatible Serialization + +To assist the migration from GTMOAuth2 to GTMAppAuth, GTMOAuth2-compatible +serialization methods are provided in `GTMOAuth2KeychainCompatibility`. + +```objc +// Deserialize from Keychain +GTMAppAuthFetcherAuthorization *auth = + [GTMOAuth2KeychainCompatibility authForGoogleFromKeychainForName:kKeychainItemName + clientID:clientID + clientSecret:clientSecret]; + +// Remove from Keychain +[GTMOAuth2KeychainCompatibility removeAuthFromKeychainForName:kKeychainItemName]; +``` + +You can also serialize to GTMOAuth2 format, though this is discouraged (you +should serialize in GTMAppAuth format as described above). + +```objc +// Serialize to Keychain +[GTMOAuth2KeychainCompatibility saveAuthToKeychainForName:kKeychainItemName + authentication:authorization]; +``` + +## Included Samples + +Try out one of the included sample apps under [Examples](Examples). In the +apps folder run `pod install`, then open the resulting `xcworkspace` file. + +Be sure to follow the instructions in +[Example-iOS/README.md](Examples/Example-iOS/README.md) or +[Example-macOS/README.md](Examples/Example-macOS/README.md) to configure +your own OAuth client ID for use with the example. + +## Differences with GTMOAuth2 + +### Authorization Method + +GTMAppAuth uses the browser to present the authorization request, while +GTMOAuth2 uses an embedded web-view. Migrating to GTMAppAuth will require you +to change how you authorize the user. Follow the instructions above to get the +authorization. You can then create a `GTMAppAuthFetcherAuthorization` object +with the `initWithAuthState:authState` initializer. + +Once you have the `GTMAppAuthFetcherAuthorization` you can continue to make REST +calls as before. + +### Error Handling + +GTMAppAuth's error handling is also different. There are no notifications, +instead you need to inspect NSError in the callback. If the error domain is +`OIDOAuthTokenErrorDomain`, it indicates an authorization error, you should +clear your authorization state and consider prompting the user to authorize +again. Other errors are generally considered transient, meaning that you should +retry the request after a delay. + +### Serialization + +The serialization format is different between GTMOAuth2 and GTMAppAuth, though +we have methods to help you migrate from one to the other without losing any +data. + +## Migrating from GTMOAuth2 + +### OAuth Client Registration + +Typically, GTMOAuth2 clients are registered with Google as type "Other". This is +correct for macOS, but on iOS clients should be registered with the type "iOS". + +If you're migrating an iOS client, in the *same project as your existing client*, +[register a new iOS client](https://console.developers.google.com/apis/credentials?project=_) +to be used with GTMAppAuth. + +### Changing your Authorization Flows + +Both GTMOAuth2 and GTMAppAuth support the `GTMFetcherAuthorizationProtocol` +allowing you to use the authorization with the session fetcher. Where you +previously had a property like `GTMOAuth2Authentication *authorization` change the +type to reference the protocol instead, i.e.: +`id<GTMFetcherAuthorizationProtocol> authorization`. This allows you to switch +the authorization implementation under the hood to GTMAppAuth. + +Then, follow the instructions above to replace authorization request +(where you ask the user to grant access) with the GTMAppAuth approach. If you +created a new OAuth client, use that for these requests. + +### Serialization & Migrating Existing Grants + +GTMAppAuth has a new data format and APIs for serialization. Unlike +GTMOAuth2, GTMAppAuth serializes the configuration and history of the +authorization, including the client id, and a record of the authorization +request that resulted in the authorization grant. + +The client ID used for GTMAppAuth is [different](#oauth-client-registration) to +the one used for GTMOAuth2. In order to keep track of the different client ids +used for new and old grants, it's recommended to migrate to the new +serialization format, which will store that for you. +[GTMOAuth2-compatible serialization](#gtmoauth2-compatible-serialization) is +also offered, but not fully supported. + +Change how you serialize your `authorization` object using the new methods +using the following example. + +```objc +// Serialize to Keychain +[GTMAppAuthFetcherAuthorization saveAuthorization:(GTMAppAuthFetcherAuthorization *)authorization + toKeychainForName:kNewKeychainName]; +``` + +Be sure to use a *new* name for the keychain. Don't reuse your old one! + +For deserializing, we can preserve all existing grants (so users who authorized +your app in GTMOAuth2 don't have to authorize it again). Remember that when +deserializing the *old* data you need to use your *old* keychain name, and +the old client id and client secret (if those changed), and that when +serializing to the *new* format, use the *new* keychain name. +Once again, pay particular care to use the old details when deserializing the +GTMOAuth2 keychain, and the new details for all other GTMAppAuth calls. + +Keychain migration example: + +```objc +// Attempt to deserialize from Keychain in GTMAppAuth format. +id<GTMFetcherAuthorizationProtocol> authorization = + [GTMAppAuthFetcherAuthorization authorizationFromKeychainForName:kNewKeychainName]; + +// If no data found in the new format, try to deserialize data from GTMOAuth2 +if (!authorization) { + // Tries to load the data serialized by GTMOAuth2 using old keychain name. + // If you created a new client id, be sure to use the *previous* client id and secret here. + authorization = + [GTMOAuth2KeychainCompatibility authForGoogleFromKeychainForName:kPreviousKeychainName + clientID:kPreviousClientID + clientSecret:kPreviousClientSecret]; + if (authorization) { + // Remove previously stored GTMOAuth2-formatted data. + [GTMOAuth2KeychainCompatibility removeAuthFromKeychainForName:kPreviousKeychainName]; + // Serialize to Keychain in GTMAppAuth format. + [GTMAppAuthFetcherAuthorization saveAuthorization:(GTMAppAuthFetcherAuthorization *)authorization + toKeychainForName:kNewKeychainName]; + } +} +``` 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 |
