[Pods] Updates GoogleSignIn dependency to 5.0.2
* GoogleSignIn (4.4.0 -> 5.0.2) * GTMSessionFetcher (1.5.0 -> 1.7.2) * GoogleToolboxForMac (Removed)
This commit is contained in:
parent
00121bd31f
commit
08a40b3516
2
External/Harmony
vendored
2
External/Harmony
vendored
@ -1 +1 @@
|
||||
Subproject commit 7234d6626a49e56ddceaaec0c04cc4f4f43b572c
|
||||
Subproject commit b72a3fdd4e2a3fe1d34b4b9ca75cbe352570a9f2
|
||||
47
Podfile.lock
47
Podfile.lock
@ -1,5 +1,11 @@
|
||||
PODS:
|
||||
- Alamofire (4.7.3)
|
||||
- AppAuth (1.6.2):
|
||||
- AppAuth/Core (= 1.6.2)
|
||||
- AppAuth/ExternalUserAgent (= 1.6.2)
|
||||
- AppAuth/Core (1.6.2)
|
||||
- AppAuth/ExternalUserAgent (1.6.2):
|
||||
- AppAuth/Core
|
||||
- Crashlytics (3.8.6):
|
||||
- Fabric (~> 1.6.3)
|
||||
- DeltaCore (0.1):
|
||||
@ -16,30 +22,25 @@ PODS:
|
||||
- GoogleAPIClientForREST/Drive (1.3.11):
|
||||
- GoogleAPIClientForREST/Core
|
||||
- GTMSessionFetcher (>= 1.1.7)
|
||||
- GoogleSignIn (4.4.0):
|
||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)"
|
||||
- GoogleSignIn (5.0.2):
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleToolboxForMac/DebugUtils (2.3.0):
|
||||
- GoogleToolboxForMac/Defines (= 2.3.0)
|
||||
- GoogleToolboxForMac/Defines (2.3.0)
|
||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (2.3.0)":
|
||||
- GoogleToolboxForMac/DebugUtils (= 2.3.0)
|
||||
- GoogleToolboxForMac/Defines (= 2.3.0)
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (= 2.3.0)"
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (2.3.0)"
|
||||
- GTMSessionFetcher (1.5.0):
|
||||
- GTMSessionFetcher/Full (= 1.5.0)
|
||||
- GTMSessionFetcher/Core (1.5.0)
|
||||
- GTMSessionFetcher/Full (1.5.0):
|
||||
- GTMSessionFetcher/Core (= 1.5.0)
|
||||
- GTMAppAuth (1.3.1):
|
||||
- AppAuth/Core (~> 1.6)
|
||||
- GTMSessionFetcher/Core (< 3.0, >= 1.5)
|
||||
- GTMSessionFetcher (1.7.2):
|
||||
- GTMSessionFetcher/Full (= 1.7.2)
|
||||
- GTMSessionFetcher/Core (1.7.2)
|
||||
- GTMSessionFetcher/Full (1.7.2):
|
||||
- GTMSessionFetcher/Core (= 1.7.2)
|
||||
- Harmony (0.1):
|
||||
- Harmony/Harmony-Drive (= 0.1)
|
||||
- Harmony/Harmony-Dropbox (= 0.1)
|
||||
- Roxas
|
||||
- Harmony/Harmony-Drive (0.1):
|
||||
- GoogleAPIClientForREST/Drive (~> 1.3.0)
|
||||
- GoogleSignIn (~> 4.4.0)
|
||||
- GoogleSignIn (~> 5.0)
|
||||
- Roxas
|
||||
- Harmony/Harmony-Dropbox (0.1):
|
||||
- Roxas
|
||||
@ -90,11 +91,12 @@ DEPENDENCIES:
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Alamofire
|
||||
- AppAuth
|
||||
- Crashlytics
|
||||
- Fabric
|
||||
- GoogleAPIClientForREST
|
||||
- GoogleSignIn
|
||||
- GoogleToolboxForMac
|
||||
- GTMAppAuth
|
||||
- GTMSessionFetcher
|
||||
- SDWebImage
|
||||
- SMCalloutView
|
||||
@ -126,6 +128,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568
|
||||
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
|
||||
Crashlytics: e156f27e43abaa331f9b7afed091bda37e1052cc
|
||||
DeltaCore: 6a430005ea397fcd5b40b964effe41ac69cc9037
|
||||
DSDeltaCore: d22a7cfbbe70f063b8c72dec9d1bcd2c59e14893
|
||||
@ -133,10 +136,10 @@ SPEC CHECKSUMS:
|
||||
GBADeltaCore: c2f7ce5e5616ed63d2b99c9ba9a7e020f2263248
|
||||
GBCDeltaCore: 27f09a1c88a4ac832aa549fbe34aaf277251b6b8
|
||||
GoogleAPIClientForREST: 0f19a8280dfe6471f76016645d26eb5dae305101
|
||||
GoogleSignIn: 7ff245e1a7b26d379099d3243a562f5747e23d39
|
||||
GoogleToolboxForMac: 1350d40e86a76f7863928d63bcb0b89c84c521c5
|
||||
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
|
||||
Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96
|
||||
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
||||
GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
|
||||
GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba
|
||||
Harmony: 5fdc51d0a4f2ce7dcd4439becbbdda1fac4c9e3f
|
||||
MelonDSDeltaCore: 46193f4fd88e4e18e4a5c841b1ae02dc46d1daa6
|
||||
N64DeltaCore: 4eeb468746722952bcd5467ecb9ebe7df070f53a
|
||||
NESDeltaCore: ffae3bba878fc505bac0914150a695ede7bc9550
|
||||
|
||||
717
Pods/AppAuth/README.md
generated
Normal file
717
Pods/AppAuth/README.md
generated
Normal file
@ -0,0 +1,717 @@
|
||||

|
||||
[](https://github.com/openid/AppAuth-iOS/actions/workflows/tests.yml)
|
||||
[](https://codecov.io/gh/openid/AppAuth-iOS)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://swift.org/package-manager)
|
||||
[](https://cocoapods.org/pods/AppAuth)
|
||||
[](https://github.com/openid/AppAuth-iOS/blob/master/LICENSE)
|
||||
[](https://cocoapods.org/pods/AppAuth)
|
||||
[](https://developer.apple.com/documentation/xcode/creating_a_mac_version_of_your_ipad_app)
|
||||
|
||||
AppAuth for iOS and macOS, and tvOS is a client SDK for communicating with
|
||||
[OAuth 2.0](https://tools.ietf.org/html/rfc6749) and
|
||||
[OpenID Connect](http://openid.net/specs/openid-connect-core-1_0.html) providers.
|
||||
It strives to
|
||||
directly map the requests and responses of those specifications, while following
|
||||
the idiomatic style of the implementation language. In addition to mapping the
|
||||
raw protocol flows, convenience methods are available to assist with common
|
||||
tasks like performing an action with fresh tokens.
|
||||
|
||||
It follows the best practices set out in
|
||||
[RFC 8252 - OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)
|
||||
including using `SFAuthenticationSession` and `SFSafariViewController` on iOS
|
||||
for the auth request. `UIWebView` and `WKWebView` are explicitly *not*
|
||||
supported due to the security and usability reasons explained in
|
||||
[Section 8.12 of RFC 8252](https://tools.ietf.org/html/rfc8252#section-8.12).
|
||||
|
||||
It also supports the [PKCE](https://tools.ietf.org/html/rfc7636) extension to
|
||||
OAuth, which was created to secure authorization codes in public clients when
|
||||
custom URI scheme redirects are used. The library is friendly to other
|
||||
extensions (standard or otherwise), with the ability to handle additional params
|
||||
in all protocol requests and responses.
|
||||
|
||||
For tvOS, AppAuth implements [OAuth 2.0 Device Authorization Grant
|
||||
](https://tools.ietf.org/html/rfc8628) to allow for tvOS sign-ins through a secondary device.
|
||||
|
||||
## Specification
|
||||
|
||||
### iOS
|
||||
|
||||
#### Supported Versions
|
||||
|
||||
AppAuth supports iOS 7 and above.
|
||||
|
||||
iOS 9+ uses the in-app browser tab pattern
|
||||
(via `SFSafariViewController`), and falls back to the system browser (mobile
|
||||
Safari) on earlier versions.
|
||||
|
||||
#### Authorization Server Requirements
|
||||
|
||||
Both Custom URI Schemes (all supported versions of iOS) and Universal Links
|
||||
(iOS 9+) can be used with the library.
|
||||
|
||||
In general, AppAuth can work with any authorization server that supports
|
||||
native apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252),
|
||||
either through custom URI scheme redirects, or universal links.
|
||||
Authorization servers that assume all clients are web-based, or require clients to maintain
|
||||
confidentiality of the client secrets may not work well.
|
||||
|
||||
### macOS
|
||||
|
||||
#### Supported Versions
|
||||
|
||||
AppAuth supports macOS (OS X) 10.9 and above.
|
||||
|
||||
#### Authorization Server Requirements
|
||||
|
||||
AppAuth for macOS supports both custom schemes; a loopback HTTP redirects
|
||||
via a small embedded server.
|
||||
|
||||
In general, AppAuth can work with any authorization server that supports
|
||||
native apps, as documented in [RFC 8252](https://tools.ietf.org/html/rfc8252);
|
||||
either through custom URI schemes, or loopback HTTP redirects.
|
||||
Authorization servers that assume all clients are web-based, or require clients to maintain
|
||||
confidentiality of the client secrets may not work well.
|
||||
|
||||
### tvOS
|
||||
|
||||
#### Supported Versions
|
||||
|
||||
AppAuth supports tvOS 9.0 and above. Please note that while it is possible to run the standard AppAuth library on tvOS, the documentation below describes implementing [OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/rfc8628) (AppAuthTV).
|
||||
|
||||
#### Authorization Server Requirements
|
||||
|
||||
AppAuthTV is designed for servers that support the device authorization flow as documented in [RFC 8628](https://tools.ietf.org/html/rfc8628).
|
||||
|
||||
## Try
|
||||
|
||||
Want to try out AppAuth? Just run:
|
||||
|
||||
pod try AppAuth
|
||||
|
||||
Follow the instructions in [Examples/README.md](Examples/README.md) to configure
|
||||
with your own OAuth client (you need to update three configuration points with your
|
||||
client info to try the demo).
|
||||
|
||||
## Setup
|
||||
|
||||
AppAuth supports four options for dependency management.
|
||||
|
||||
### CocoaPods
|
||||
|
||||
With [CocoaPods](https://guides.cocoapods.org/using/getting-started.html),
|
||||
add the following line to your `Podfile`:
|
||||
|
||||
pod 'AppAuth'
|
||||
|
||||
Then, run `pod install`.
|
||||
|
||||
**tvOS:** Use the `TV` subspec:
|
||||
|
||||
pod 'AppAuth/TV'
|
||||
|
||||
|
||||
### Swift Package Manager
|
||||
|
||||
With [Swift Package Manager](https://swift.org/package-manager),
|
||||
add the following `dependency` to your `Package.swift`:
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/openid/AppAuth-iOS.git", .upToNextMajor(from: "1.3.0"))
|
||||
]
|
||||
```
|
||||
|
||||
**tvOS:** Use the `AppAuthTV` target.
|
||||
|
||||
### Carthage
|
||||
|
||||
With [Carthage](https://github.com/Carthage/Carthage), add the following
|
||||
line to your `Cartfile`:
|
||||
|
||||
github "openid/AppAuth-iOS" "master"
|
||||
|
||||
Then, run `carthage bootstrap`.
|
||||
|
||||
**tvOS:** Use the `AppAuthTV` framework.
|
||||
|
||||
### Static Library
|
||||
|
||||
You can also use AppAuth as a static library. This requires linking the library
|
||||
and your project, and including the headers. Here is a suggested configuration:
|
||||
|
||||
1. Create an Xcode Workspace.
|
||||
2. Add `AppAuth.xcodeproj` to your Workspace.
|
||||
3. Include libAppAuth as a linked library for your target (in the "General ->
|
||||
Linked Framework and Libraries" section of your target).
|
||||
4. Add `AppAuth-iOS/Source` to your search paths of your target ("Build Settings ->
|
||||
"Header Search Paths").
|
||||
|
||||
*Note: There is no static library for AppAuthTV.*
|
||||
|
||||
## Auth Flow
|
||||
|
||||
AppAuth supports both manual interaction with the authorization server
|
||||
where you need to perform your own token exchanges, as well as convenience
|
||||
methods that perform some of this logic for you. This example uses the
|
||||
convenience method, which returns either an `OIDAuthState` object, or an error.
|
||||
|
||||
`OIDAuthState` is a class that keeps track of the authorization and token
|
||||
requests and responses, and provides a convenience method to call an API with
|
||||
fresh tokens. This is the only object that you need to serialize to retain the
|
||||
authorization state of the session.
|
||||
|
||||
### Configuration
|
||||
|
||||
You can configure AppAuth by specifying the endpoints directly:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```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...
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
let authorizationEndpoint = URL(string: "https://accounts.google.com/o/oauth2/v2/auth")!
|
||||
let tokenEndpoint = URL(string: "https://www.googleapis.com/oauth2/v4/token")!
|
||||
let configuration = OIDServiceConfiguration(authorizationEndpoint: authorizationEndpoint,
|
||||
tokenEndpoint: tokenEndpoint)
|
||||
|
||||
// perform the auth request...
|
||||
```
|
||||
|
||||
**tvOS**
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
NSURL *deviceAuthorizationEndpoint =
|
||||
[NSURL URLWithString:@"https://oauth2.googleapis.com/device/code"];
|
||||
NSURL *tokenEndpoint =
|
||||
[NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"];
|
||||
|
||||
OIDTVServiceConfiguration *configuration =
|
||||
[[OIDTVServiceConfiguration alloc]
|
||||
initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint];
|
||||
|
||||
// perform the auth request...
|
||||
```
|
||||
|
||||
|
||||
Or through discovery:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```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...
|
||||
}];
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
let issuer = URL(string: "https://accounts.google.com")!
|
||||
|
||||
// discovers endpoints
|
||||
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in
|
||||
guard let config = configuration else {
|
||||
print("Error retrieving discovery document: \(error?.localizedDescription ?? "Unknown error")")
|
||||
return
|
||||
}
|
||||
|
||||
// perform the auth request...
|
||||
}
|
||||
```
|
||||
|
||||
**tvOS**
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
NSURL *issuer = [NSURL URLWithString:@"https://accounts.google.com"];
|
||||
|
||||
[OIDTVAuthorizationService discoverServiceConfigurationForIssuer:issuer
|
||||
completion:^(OIDTVServiceConfiguration *_Nullable configuration,
|
||||
NSError *_Nullable error) {
|
||||
|
||||
if (!configuration) {
|
||||
NSLog(@"Error retrieving discovery document: %@",
|
||||
[error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
// perform the auth request...
|
||||
}];
|
||||
```
|
||||
|
||||
### Authorizing – iOS
|
||||
|
||||
First, you need to have a property in your `UIApplicationDelegate`
|
||||
implementation to hold the session, in order to continue the authorization flow
|
||||
from the redirect. In this example, the implementation of this delegate is
|
||||
a class named `AppDelegate`, if your app's application delegate has a different
|
||||
name, please update the class name in samples below accordingly.
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
// property of the app's AppDelegate
|
||||
@property(nonatomic, strong, nullable) id<OIDExternalUserAgentSession> currentAuthorizationFlow;
|
||||
@end
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// property of the app's AppDelegate
|
||||
var currentAuthorizationFlow: OIDExternalUserAgentSession?
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
And your main class, a property to store the auth state:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
// property of the containing class
|
||||
@property(nonatomic, strong, nullable) OIDAuthState *authState;
|
||||
```
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
// property of the containing class
|
||||
private var authState: OIDAuthState?
|
||||
```
|
||||
|
||||
|
||||
Then, initiate the authorization request. By using the
|
||||
`authStateByPresentingAuthorizationRequest` convenience method, the token
|
||||
exchange will be performed automatically, and everything will be protected with
|
||||
PKCE (if the server supports it). AppAuth also lets you perform these
|
||||
requests manually. See the `authNoCodeExchange` method in the included Example
|
||||
app for a demonstration:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
// builds authentication request
|
||||
OIDAuthorizationRequest *request =
|
||||
[[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
|
||||
clientId:kClientID
|
||||
scopes:@[OIDScopeOpenID,
|
||||
OIDScopeProfile]
|
||||
redirectURL:kRedirectURI
|
||||
responseType:OIDResponseTypeCode
|
||||
additionalParameters:nil];
|
||||
|
||||
// performs authentication request
|
||||
AppDelegate *appDelegate =
|
||||
(AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appDelegate.currentAuthorizationFlow =
|
||||
[OIDAuthState authStateByPresentingAuthorizationRequest:request
|
||||
presentingViewController:self
|
||||
callback:^(OIDAuthState *_Nullable authState,
|
||||
NSError *_Nullable error) {
|
||||
if (authState) {
|
||||
NSLog(@"Got authorization tokens. Access token: %@",
|
||||
authState.lastTokenResponse.accessToken);
|
||||
[self setAuthState:authState];
|
||||
} else {
|
||||
NSLog(@"Authorization error: %@", [error localizedDescription]);
|
||||
[self setAuthState:nil];
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
// builds authentication request
|
||||
let request = OIDAuthorizationRequest(configuration: configuration,
|
||||
clientId: clientID,
|
||||
clientSecret: clientSecret,
|
||||
scopes: [OIDScopeOpenID, OIDScopeProfile],
|
||||
redirectURL: redirectURI,
|
||||
responseType: OIDResponseTypeCode,
|
||||
additionalParameters: nil)
|
||||
|
||||
// performs authentication request
|
||||
print("Initiating authorization request with scope: \(request.scope ?? "nil")")
|
||||
|
||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||
|
||||
appDelegate.currentAuthorizationFlow =
|
||||
OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
|
||||
if let authState = authState {
|
||||
self.setAuthState(authState)
|
||||
print("Got authorization tokens. Access token: " +
|
||||
"\(authState.lastTokenResponse?.accessToken ?? "nil")")
|
||||
} else {
|
||||
print("Authorization error: \(error?.localizedDescription ?? "Unknown error")")
|
||||
self.setAuthState(nil)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*Handling the Redirect*
|
||||
|
||||
The authorization response URL is returned to the app via the iOS openURL
|
||||
app delegate method, so you need to pipe this through to the current
|
||||
authorization session (created in the previous session):
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```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;
|
||||
}
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
func application(_ app: UIApplication,
|
||||
open url: URL,
|
||||
options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
|
||||
// Sends the URL to the current authorization flow (if any) which will
|
||||
// process it if it relates to an authorization response.
|
||||
if let authorizationFlow = self.currentAuthorizationFlow,
|
||||
authorizationFlow.resumeExternalUserAgentFlow(with: url) {
|
||||
self.currentAuthorizationFlow = nil
|
||||
return true
|
||||
}
|
||||
|
||||
// Your additional URL handling (if any)
|
||||
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
### Authorizing – MacOS
|
||||
|
||||
On macOS, the most popular way to get the authorization response redirect is to
|
||||
start a local HTTP server on the loopback interface (limited to incoming
|
||||
requests from the user's machine only). When the authorization is complete, the
|
||||
user is redirected to that local server, and the authorization response can be
|
||||
processed by the app. AppAuth takes care of managing the local HTTP server
|
||||
lifecycle for you.
|
||||
|
||||
> #### :bulb: Alternative: Custom URI Schemes
|
||||
> Custom URI schemes are also supported on macOS, but some browsers display
|
||||
> an interstitial, which reduces the usability. For an example on using custom
|
||||
> URI schemes with macOS, See `Example-Mac`.
|
||||
|
||||
To receive the authorization response using a local HTTP server, first you need
|
||||
to have an instance variable in your main class to retain the HTTP redirect
|
||||
handler:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
OIDRedirectHTTPHandler *_redirectHTTPHandler;
|
||||
```
|
||||
|
||||
Then, as the port used by the local HTTP server varies, you need to start it
|
||||
before building the authorization request, in order to get the exact redirect
|
||||
URI to use:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
static NSString *const kSuccessURLString =
|
||||
@"http://openid.github.io/AppAuth-iOS/redirect/";
|
||||
NSURL *successURL = [NSURL URLWithString:kSuccessURLString];
|
||||
|
||||
// Starts a loopback HTTP redirect listener to receive the code. This needs to be started first,
|
||||
// as the exact redirect URI (including port) must be passed in the authorization request.
|
||||
_redirectHTTPHandler = [[OIDRedirectHTTPHandler alloc] initWithSuccessURL:successURL];
|
||||
NSURL *redirectURI = [_redirectHTTPHandler startHTTPListener:nil];
|
||||
```
|
||||
|
||||
Then, initiate the authorization request. By using the
|
||||
`authStateByPresentingAuthorizationRequest` convenience method, the token
|
||||
exchange will be performed automatically, and everything will be protected with
|
||||
PKCE (if the server supports it). By assigning the return value to the
|
||||
`OIDRedirectHTTPHandler`'s `currentAuthorizationFlow`, the authorization will
|
||||
continue automatically once the user makes their choice:
|
||||
|
||||
```objc
|
||||
// builds authentication request
|
||||
OIDAuthorizationRequest *request =
|
||||
[[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
|
||||
clientId:kClientID
|
||||
clientSecret:kClientSecret
|
||||
scopes:@[ OIDScopeOpenID ]
|
||||
redirectURL:redirectURI
|
||||
responseType:OIDResponseTypeCode
|
||||
additionalParameters:nil];
|
||||
// performs authentication request
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
_redirectHTTPHandler.currentAuthorizationFlow =
|
||||
[OIDAuthState authStateByPresentingAuthorizationRequest:request
|
||||
callback:^(OIDAuthState *_Nullable authState,
|
||||
NSError *_Nullable error) {
|
||||
// Brings this app to the foreground.
|
||||
[[NSRunningApplication currentApplication]
|
||||
activateWithOptions:(NSApplicationActivateAllWindows |
|
||||
NSApplicationActivateIgnoringOtherApps)];
|
||||
|
||||
// Processes the authorization response.
|
||||
if (authState) {
|
||||
NSLog(@"Got authorization tokens. Access token: %@",
|
||||
authState.lastTokenResponse.accessToken);
|
||||
} else {
|
||||
NSLog(@"Authorization error: %@", error.localizedDescription);
|
||||
}
|
||||
[weakSelf setAuthState:authState];
|
||||
}];
|
||||
```
|
||||
|
||||
|
||||
### Authorizing – tvOS
|
||||
|
||||
Ensure that your main class is a delegate of `OIDAuthStateChangeDelegate`, `OIDAuthStateErrorDelegate`, implement the corresponding methods, and include the following property and instance variable:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
// property of the containing class
|
||||
@property(nonatomic, strong, nullable) OIDAuthState *authState;
|
||||
|
||||
// instance variable of the containing class
|
||||
OIDTVAuthorizationCancelBlock _cancelBlock;
|
||||
```
|
||||
|
||||
Then, build and perform the authorization request.
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
// builds authentication request
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
OIDTVAuthorizationRequest *request =
|
||||
[[OIDTVAuthorizationRequest alloc] initWithConfiguration:configuration
|
||||
clientId:kClientID
|
||||
clientSecret:kClientSecret
|
||||
scopes:@[ OIDScopeOpenID, OIDScopeProfile ]
|
||||
additionalParameters:nil];
|
||||
|
||||
// performs authentication request
|
||||
OIDTVAuthorizationInitialization initBlock =
|
||||
^(OIDTVAuthorizationResponse *_Nullable response, NSError *_Nullable error) {
|
||||
if (response) {
|
||||
// process authorization response
|
||||
NSLog(@"Got authorization response: %@", response);
|
||||
} else {
|
||||
// handle initialization error
|
||||
NSLog(@"Error: %@", error);
|
||||
}
|
||||
};
|
||||
|
||||
OIDTVAuthorizationCompletion completionBlock =
|
||||
^(OIDAuthState *_Nullable authState, NSError *_Nullable error) {
|
||||
weakSelf.signInView.hidden = YES;
|
||||
if (authState) {
|
||||
NSLog(@"Token response: %@", authState.lastTokenResponse);
|
||||
[weakSelf setAuthState:authState];
|
||||
} else {
|
||||
NSLog(@"Error: %@", error);
|
||||
[weakSelf setAuthState:nil];
|
||||
}
|
||||
};
|
||||
|
||||
_cancelBlock = [OIDTVAuthorizationService authorizeTVRequest:request
|
||||
initialization:initBlock
|
||||
completion:completionBlock];
|
||||
```
|
||||
|
||||
### Making API Calls
|
||||
|
||||
AppAuth gives you the raw token information, if you need it. However, we
|
||||
recommend that users of the `OIDAuthState` convenience wrapper use the provided
|
||||
`performActionWithFreshTokens:` method to perform their API calls to avoid
|
||||
needing to worry about token freshness:
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
[_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken,
|
||||
NSString *_Nonnull idToken,
|
||||
NSError *_Nullable error) {
|
||||
if (error) {
|
||||
NSLog(@"Error fetching fresh tokens: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
// perform your API request using the tokens
|
||||
}];
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```swift
|
||||
let userinfoEndpoint = URL(string:"https://openidconnect.googleapis.com/v1/userinfo")!
|
||||
self.authState?.performAction() { (accessToken, idToken, error) in
|
||||
|
||||
if error != nil {
|
||||
print("Error fetching fresh tokens: \(error?.localizedDescription ?? "Unknown error")")
|
||||
return
|
||||
}
|
||||
guard let accessToken = accessToken else {
|
||||
return
|
||||
}
|
||||
|
||||
// Add Bearer token to request
|
||||
var urlRequest = URLRequest(url: userinfoEndpoint)
|
||||
urlRequest.allHTTPHeaderFields = ["Authorization": "Bearer \(accessToken)"]
|
||||
|
||||
// Perform request...
|
||||
}
|
||||
```
|
||||
|
||||
### Custom User-Agents (iOS and macOS)
|
||||
|
||||
Each OAuth flow involves presenting an external user-agent to the user, that
|
||||
allows them to interact with the OAuth authorization server. Typical examples
|
||||
of a user-agent are the user's browser, or an in-app browser tab incarnation
|
||||
like `ASWebAuthenticationSession` on iOS.
|
||||
|
||||
AppAuth ships with several implementations of an external user-agent out of the
|
||||
box, including defaults for iOS and macOS suitable for most cases. The default
|
||||
user-agents typically share persistent cookies with the system default browser,
|
||||
to improve the chance that the user doesn't need to sign-in all over again.
|
||||
|
||||
It is possible to change the user-agent that AppAuth uses, and even write your
|
||||
own - all without needing to fork the library.
|
||||
|
||||
All implementations of the external user-agent, be they included or created by
|
||||
you need to conform to the
|
||||
[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)
|
||||
protocol.
|
||||
|
||||
Instances of the `OIDExternalUserAgent`are passed into
|
||||
[`OIDAuthState.authStateByPresentingAuthorizationRequest:externalUserAgent:callback`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_auth_state.html#ac762fe2bf95c116f0b437419be211fa1)
|
||||
and/or
|
||||
[`OIDAuthorizationService.presentAuthorizationRequest:externalUserAgent:callback:`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_authorization_service.html#ae551f8e6887366a46e49b09b37389b8f)
|
||||
rather than using the platform-specific convenience methods (which use the
|
||||
default user-agents for their respective platforms), like
|
||||
[`OIDAuthState.authStateByPresentingAuthorizationRequest:presentingViewController:callback:`](http://openid.github.io/AppAuth-iOS/docs/latest/category_o_i_d_auth_state_07_i_o_s_08.html#ae32fd0732cd3192cd5219f2655a4c85c).
|
||||
|
||||
Popular use-cases for writing your own user-agent implementation include needing
|
||||
to style the user-agent in ways not supported by AppAuth, and implementing a
|
||||
fully custom flow with your own business logic. You can take one of the existing
|
||||
implementations as a starting point to copy, rename, and customize to your
|
||||
needs.
|
||||
|
||||
#### Custom Browser User-Agent
|
||||
|
||||
AppAuth for iOS includes a few extra user-agent implementations which you can
|
||||
try, or use as a reference for your own implementation. One of them,
|
||||
[`OIDExternalUserAgentIOSCustomBrowser`](http://openid.github.io/AppAuth-iOS/docs/latest/interface_o_i_d_external_user_agent_i_o_s_custom_browser.html)
|
||||
enables you to use a different browser for authentication, like Chrome for iOS
|
||||
or Firefox for iOS.
|
||||
|
||||
Here's how to configure AppAuth to use a custom browser using the
|
||||
`OIDExternalUserAgentIOSCustomBrowser` user agent:
|
||||
|
||||
First, add the following array to your
|
||||
[Info.plist](https://github.com/openid/AppAuth-iOS/blob/135f99d2cb4e9d18d310ac2588b905e612461561/Examples/Example-iOS_ObjC/Source/Info.plist#L34)
|
||||
(in XCode, right click -> Open As -> Source Code)
|
||||
|
||||
```
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>googlechromes</string>
|
||||
<string>opera-https</string>
|
||||
<string>firefox</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
This is required so that AppAuth can test for the browser and open the app store
|
||||
if it's not installed (the default behavior of this user-agent). You only need
|
||||
to include the URL scheme of the actual browser you intend to use.
|
||||
|
||||
<sub>Objective-C</sub>
|
||||
```objc
|
||||
// performs authentication request
|
||||
AppDelegate *appDelegate =
|
||||
(AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
id<OIDExternalUserAgent> userAgent =
|
||||
[OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome];
|
||||
appDelegate.currentAuthorizationFlow =
|
||||
[OIDAuthState authStateByPresentingAuthorizationRequest:request
|
||||
externalUserAgent:userAgent
|
||||
callback:^(OIDAuthState *_Nullable authState,
|
||||
NSError *_Nullable error) {
|
||||
if (authState) {
|
||||
NSLog(@"Got authorization tokens. Access token: %@",
|
||||
authState.lastTokenResponse.accessToken);
|
||||
[self setAuthState:authState];
|
||||
} else {
|
||||
NSLog(@"Authorization error: %@", [error localizedDescription]);
|
||||
[self setAuthState:nil];
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
<sub>Swift</sub>
|
||||
```
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
|
||||
self.logMessage("Error accessing AppDelegate")
|
||||
return
|
||||
}
|
||||
let userAgent = OIDExternalUserAgentIOSCustomBrowser.customBrowserChrome()
|
||||
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, externalUserAgent: userAgent) { authState, error in
|
||||
if let authState = authState {
|
||||
self.setAuthState(authState)
|
||||
self.logMessage("Got authorization tokens. Access token: \(authState.lastTokenResponse?.accessToken ?? "DEFAULT_TOKEN")")
|
||||
} else {
|
||||
self.logMessage("Authorization error: \(error?.localizedDescription ?? "DEFAULT_ERROR")")
|
||||
self.setAuthState(nil)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That's it! With those two changes (which you can try on the included sample),
|
||||
AppAuth will use Chrome iOS for the authorization request (and open Chrome in
|
||||
the App Store if it's not installed).
|
||||
|
||||
⚠️**Note: the `OIDExternalUserAgentIOSCustomBrowser` user-agent is not intended for consumer apps**. It is designed for
|
||||
advanced enterprise use-cases where the app developers have greater control over
|
||||
the operating environment and have special requirements that require a custom
|
||||
browser like Chrome.
|
||||
|
||||
You don't need to stop with the included external user agents either! Since the
|
||||
[`OIDExternalUserAgent`](http://openid.github.io/AppAuth-iOS/docs/latest/protocol_o_i_d_external_user_agent-p.html)
|
||||
protocol is part of AppAuth's public API, you can implement your own versions of
|
||||
it. In the above example,
|
||||
`userAgent = [OIDExternalUserAgentIOSCustomBrowser CustomBrowserChrome]` would
|
||||
be replaced with an instantiation of your user-agent implementation.
|
||||
|
||||
## API Documentation
|
||||
|
||||
Browse the [API documentation](http://openid.github.io/AppAuth-iOS/docs/latest/annotated.html).
|
||||
|
||||
## Included Samples
|
||||
|
||||
Sample apps that explore core AppAuth features are available for iOS, macOS and tvOS; follow the instructions in [Examples/README.md](Examples/README.md) to get started.
|
||||
92
Pods/AppAuth/Source/AppAuth.h
generated
Normal file
92
Pods/AppAuth/Source/AppAuth.h
generated
Normal file
@ -0,0 +1,92 @@
|
||||
/*! @file AppAuth.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthState.h"
|
||||
#import "OIDAuthStateChangeDelegate.h"
|
||||
#import "OIDAuthStateErrorDelegate.h"
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDAuthorizationResponse.h"
|
||||
#import "OIDAuthorizationService.h"
|
||||
#import "OIDError.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDExternalUserAgent.h"
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
#import "OIDGrantTypes.h"
|
||||
#import "OIDIDToken.h"
|
||||
#import "OIDRegistrationRequest.h"
|
||||
#import "OIDRegistrationResponse.h"
|
||||
#import "OIDResponseTypes.h"
|
||||
#import "OIDScopes.h"
|
||||
#import "OIDScopeUtilities.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDServiceDiscovery.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenResponse.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
#import "OIDURLSessionProvider.h"
|
||||
#import "OIDEndSessionRequest.h"
|
||||
#import "OIDEndSessionResponse.h"
|
||||
|
||||
#if TARGET_OS_TV
|
||||
#elif TARGET_OS_WATCH
|
||||
#elif TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
#import "OIDAuthState+IOS.h"
|
||||
#import "OIDAuthorizationService+IOS.h"
|
||||
#import "OIDExternalUserAgentIOS.h"
|
||||
#import "OIDExternalUserAgentIOSCustomBrowser.h"
|
||||
#import "OIDExternalUserAgentCatalyst.h"
|
||||
#elif TARGET_OS_OSX
|
||||
#import "OIDAuthState+Mac.h"
|
||||
#import "OIDAuthorizationService+Mac.h"
|
||||
#import "OIDExternalUserAgentMac.h"
|
||||
#import "OIDRedirectHTTPHandler.h"
|
||||
#else
|
||||
#error "Platform Undefined"
|
||||
#endif
|
||||
|
||||
/*! @mainpage AppAuth for iOS and macOS
|
||||
|
||||
@section introduction Introduction
|
||||
|
||||
AppAuth for iOS and macOS is a client SDK for communicating with [OAuth 2.0]
|
||||
(https://tools.ietf.org/html/rfc6749) and [OpenID Connect]
|
||||
(http://openid.net/specs/openid-connect-core-1_0.html) providers. It strives to
|
||||
directly map the requests and responses of those specifications, while following
|
||||
the idiomatic style of the implementation language. In addition to mapping the
|
||||
raw protocol flows, convenience methods are available to assist with common
|
||||
tasks like performing an action with fresh tokens.
|
||||
|
||||
It follows the best practices set out in
|
||||
[RFC 8252 - OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)
|
||||
including using `SFAuthenticationSession` and `SFSafariViewController` on iOS
|
||||
for the auth request. Web view and `WKWebView` are explicitly *not*
|
||||
supported due to the security and usability reasons explained in
|
||||
[Section 8.12 of RFC 8252](https://tools.ietf.org/html/rfc8252#section-8.12).
|
||||
|
||||
It also supports the [PKCE](https://tools.ietf.org/html/rfc7636) extension to
|
||||
OAuth which was created to secure authorization codes in public clients when
|
||||
custom URI scheme redirects are used. The library is friendly to other
|
||||
extensions (standard or otherwise) with the ability to handle additional params
|
||||
in all protocol requests and responses.
|
||||
|
||||
<b>Homepage</b>: http://openid.github.io/AppAuth-iOS/ <br>
|
||||
<b>API Documentation</b>: http://openid.github.io/AppAuth-iOS/docs/latest <br>
|
||||
<b>Git Repository</b>: https://github.com/openid/AppAuth-iOS <br>
|
||||
|
||||
*/
|
||||
84
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthState+IOS.h
generated
Normal file
84
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthState+IOS.h
generated
Normal file
@ -0,0 +1,84 @@
|
||||
/*! @file OIDAuthState+IOS.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "OIDAuthState.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief iOS specific convenience methods for @c OIDAuthState.
|
||||
*/
|
||||
@interface OIDAuthState (IOS)
|
||||
|
||||
/*! @brief Convenience method to create a @c OIDAuthState by presenting an authorization request
|
||||
and performing the authorization code exchange in the case of code flow requests. For
|
||||
the hybrid flow, the caller should validate the id_token and c_hash, then perform the token
|
||||
request (@c OIDAuthorizationService.performTokenRequest:callback:)
|
||||
and update the OIDAuthState with the results (@c
|
||||
OIDAuthState.updateWithTokenResponse:error:).
|
||||
@param authorizationRequest The authorization request to present.
|
||||
@param presentingViewController The view controller to use for presenting the authentication UI.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback;
|
||||
|
||||
/*! @brief Convenience method to create a @c OIDAuthState by presenting an authorization request
|
||||
(optionally using an emphemeral browser session that shares no cookies or data with the
|
||||
normal browser session) and performing the authorization code exchange in the case of code
|
||||
flow requests. For the hybrid flow, the caller should validate the id_token and c_hash, then
|
||||
perform the token request (@c OIDAuthorizationService.performTokenRequest:callback:)
|
||||
and update the OIDAuthState with the results (@c
|
||||
OIDAuthState.updateWithTokenResponse:error:).
|
||||
@param authorizationRequest The authorization request to present.
|
||||
@param presentingViewController The view controller to use for presenting the authentication UI.
|
||||
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
|
||||
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback
|
||||
API_AVAILABLE(ios(13));
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback API_AVAILABLE(ios(11)) API_UNAVAILABLE(macCatalyst)
|
||||
__deprecated_msg("This method will not work on iOS 13. Use "
|
||||
"authStateByPresentingAuthorizationRequest:presentingViewController:callback:");
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
78
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthState+IOS.m
generated
Normal file
78
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthState+IOS.m
generated
Normal file
@ -0,0 +1,78 @@
|
||||
/*! @file OIDAuthState+IOS.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import "OIDAuthState+IOS.h"
|
||||
#import "OIDExternalUserAgentIOS.h"
|
||||
#import "OIDExternalUserAgentCatalyst.h"
|
||||
|
||||
@implementation OIDAuthState (IOS)
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback {
|
||||
id<OIDExternalUserAgent> externalUserAgent;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
|
||||
initWithPresentingViewController:presentingViewController];
|
||||
#else // TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentIOS alloc] initWithPresentingViewController:presentingViewController];
|
||||
#endif // TARGET_OS_MACCATALYST
|
||||
return [self authStateByPresentingAuthorizationRequest:authorizationRequest
|
||||
externalUserAgent:externalUserAgent
|
||||
callback:callback];
|
||||
}
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback {
|
||||
id<OIDExternalUserAgent> externalUserAgent;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
|
||||
initWithPresentingViewController:presentingViewController
|
||||
prefersEphemeralSession:prefersEphemeralSession];
|
||||
#else // TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentIOS alloc]
|
||||
initWithPresentingViewController:presentingViewController
|
||||
prefersEphemeralSession:prefersEphemeralSession];
|
||||
#endif // TARGET_OS_MACCATALYST
|
||||
return [self authStateByPresentingAuthorizationRequest:authorizationRequest
|
||||
externalUserAgent:externalUserAgent
|
||||
callback:callback];
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback {
|
||||
OIDExternalUserAgentIOS *externalUserAgent = [[OIDExternalUserAgentIOS alloc] init];
|
||||
return [self authStateByPresentingAuthorizationRequest:authorizationRequest
|
||||
externalUserAgent:externalUserAgent
|
||||
callback:callback];
|
||||
}
|
||||
#endif // !TARGET_OS_MACCATALYST
|
||||
|
||||
@end
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
67
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h
generated
Normal file
67
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthorizationService+IOS.h
generated
Normal file
@ -0,0 +1,67 @@
|
||||
/*! @file OIDAuthorizationService+IOS.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "OIDAuthorizationService.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Provides iOS specific authorization request handling.
|
||||
*/
|
||||
@interface OIDAuthorizationService (IOS)
|
||||
|
||||
/*! @brief Perform an authorization flow, presenting an appropriate browser for the user to
|
||||
authenticate.
|
||||
@param request The authorization request.
|
||||
@param presentingViewController The view controller from which to present authentication UI.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
callback:(OIDAuthorizationCallback)callback;
|
||||
|
||||
/*! @brief Perform an authorization flow using the @c ASWebAuthenticationSession optionally using an
|
||||
emphemeral browser session that shares no cookies or data with the normal browser session.
|
||||
@param request The authorization request.
|
||||
@param presentingViewController The view controller from which to present authentication UI.
|
||||
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
|
||||
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession
|
||||
callback:(OIDAuthorizationCallback)callback API_AVAILABLE(ios(13));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
64
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m
generated
Normal file
64
Pods/AppAuth/Source/AppAuth/iOS/OIDAuthorizationService+IOS.m
generated
Normal file
@ -0,0 +1,64 @@
|
||||
/*! @file OIDAuthorizationService+IOS.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import "OIDAuthorizationService+IOS.h"
|
||||
#import "OIDExternalUserAgentIOS.h"
|
||||
#import "OIDExternalUserAgentCatalyst.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OIDAuthorizationService (IOS)
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
callback:(OIDAuthorizationCallback)callback {
|
||||
id<OIDExternalUserAgent> externalUserAgent;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
|
||||
initWithPresentingViewController:presentingViewController];
|
||||
#else // TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentIOS alloc] initWithPresentingViewController:presentingViewController];
|
||||
#endif // TARGET_OS_MACCATALYST
|
||||
return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback];
|
||||
}
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
presentingViewController:(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession
|
||||
callback:(OIDAuthorizationCallback)callback {
|
||||
id<OIDExternalUserAgent> externalUserAgent;
|
||||
#if TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentCatalyst alloc]
|
||||
initWithPresentingViewController:presentingViewController
|
||||
prefersEphemeralSession:prefersEphemeralSession];
|
||||
#else // TARGET_OS_MACCATALYST
|
||||
externalUserAgent = [[OIDExternalUserAgentIOS alloc] initWithPresentingViewController:presentingViewController
|
||||
prefersEphemeralSession:prefersEphemeralSession];
|
||||
#endif // TARGET_OS_MACCATALYST
|
||||
return [self presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:callback];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
61
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h
generated
Normal file
61
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.h
generated
Normal file
@ -0,0 +1,61 @@
|
||||
/*! @file OIDExternalUserAgentCatalyst.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2019 The AppAuth Authors. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "OIDExternalUserAgent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief A Catalyst specific external user-agent that uses `ASWebAuthenticationSession` to
|
||||
present the request.
|
||||
*/
|
||||
API_AVAILABLE(macCatalyst(13)) API_UNAVAILABLE(ios)
|
||||
@interface OIDExternalUserAgentCatalyst : NSObject<OIDExternalUserAgent>
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithPresentingViewController:
|
||||
*/
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief The designated initializer.
|
||||
@param presentingViewController The view controller from which to present the
|
||||
\SFSafariViewController.
|
||||
*/
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Create an external user-agent which optionally uses a private authentication session.
|
||||
@param presentingViewController The view controller from which to present the browser.
|
||||
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
|
||||
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
|
||||
*/
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
157
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m
generated
Normal file
157
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentCatalyst.m
generated
Normal file
@ -0,0 +1,157 @@
|
||||
/*! @file OIDExternalUserAgentCatalyst.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2019 The AppAuth Authors. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import "OIDExternalUserAgentCatalyst.h"
|
||||
|
||||
#import <SafariServices/SafariServices.h>
|
||||
#import <AuthenticationServices/AuthenticationServices.h>
|
||||
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
|
||||
#if TARGET_OS_MACCATALYST
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OIDExternalUserAgentCatalyst ()<ASWebAuthenticationPresentationContextProviding>
|
||||
@end
|
||||
|
||||
@implementation OIDExternalUserAgentCatalyst {
|
||||
UIViewController *_presentingViewController;
|
||||
BOOL _prefersEphemeralSession;
|
||||
|
||||
BOOL _externalUserAgentFlowInProgress;
|
||||
__weak id<OIDExternalUserAgentSession> _session;
|
||||
ASWebAuthenticationSession *_webAuthenticationVC;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_presentingViewController = presentingViewController;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession {
|
||||
self = [self initWithPresentingViewController:presentingViewController];
|
||||
if (self) {
|
||||
_prefersEphemeralSession = prefersEphemeralSession;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
|
||||
session:(id<OIDExternalUserAgentSession>)session {
|
||||
if (_externalUserAgentFlowInProgress) {
|
||||
// TODO: Handle errors as authorization is already in progress.
|
||||
return NO;
|
||||
}
|
||||
|
||||
_externalUserAgentFlowInProgress = YES;
|
||||
_session = session;
|
||||
BOOL openedUserAgent = NO;
|
||||
NSURL *requestURL = [request externalUserAgentRequestURL];
|
||||
|
||||
__weak OIDExternalUserAgentCatalyst *weakSelf = self;
|
||||
NSString *redirectScheme = request.redirectScheme;
|
||||
ASWebAuthenticationSession *authenticationVC =
|
||||
[[ASWebAuthenticationSession alloc] initWithURL:requestURL
|
||||
callbackURLScheme:redirectScheme
|
||||
completionHandler:^(NSURL * _Nullable callbackURL,
|
||||
NSError * _Nullable error) {
|
||||
__strong OIDExternalUserAgentCatalyst *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->_webAuthenticationVC = nil;
|
||||
if (callbackURL) {
|
||||
[strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
|
||||
} else {
|
||||
NSError *safariError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:error
|
||||
description:nil];
|
||||
[strongSelf->_session failExternalUserAgentFlowWithError:safariError];
|
||||
}
|
||||
}];
|
||||
|
||||
authenticationVC.presentationContextProvider = self;
|
||||
authenticationVC.prefersEphemeralWebBrowserSession = _prefersEphemeralSession;
|
||||
_webAuthenticationVC = authenticationVC;
|
||||
openedUserAgent = [authenticationVC start];
|
||||
|
||||
if (!openedUserAgent) {
|
||||
[self cleanUp];
|
||||
NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
|
||||
underlyingError:nil
|
||||
description:@"Unable to open ASWebAuthenticationSession view controller."];
|
||||
[session failExternalUserAgentFlowWithError:safariError];
|
||||
}
|
||||
return openedUserAgent;
|
||||
}
|
||||
|
||||
- (void)dismissExternalUserAgentAnimated:(BOOL)animated completion:(void (^)(void))completion {
|
||||
if (!_externalUserAgentFlowInProgress) {
|
||||
// Ignore this call if there is no authorization flow in progress.
|
||||
if (completion) completion();
|
||||
return;
|
||||
}
|
||||
|
||||
ASWebAuthenticationSession *webAuthenticationVC = _webAuthenticationVC;
|
||||
|
||||
[self cleanUp];
|
||||
|
||||
if (webAuthenticationVC) {
|
||||
// dismiss the ASWebAuthenticationSession
|
||||
[webAuthenticationVC cancel];
|
||||
if (completion) completion();
|
||||
} else {
|
||||
if (completion) completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanUp {
|
||||
// The weak reference to |_session| is set to nil to avoid accidentally using
|
||||
// it while not in an authorization flow.
|
||||
_webAuthenticationVC = nil;
|
||||
_session = nil;
|
||||
_externalUserAgentFlowInProgress = NO;
|
||||
}
|
||||
|
||||
#pragma mark - ASWebAuthenticationPresentationContextProviding
|
||||
|
||||
- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
|
||||
return _presentingViewController.view.window;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_MACCATALYST
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
69
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h
generated
Normal file
69
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOS.h
generated
Normal file
@ -0,0 +1,69 @@
|
||||
/*! @file OIDExternalUserAgentIOS.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "OIDExternalUserAgent.h"
|
||||
|
||||
@class SFSafariViewController;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief An iOS specific external user-agent that uses the best possible user-agent available
|
||||
depending on the version of iOS to present the request.
|
||||
*/
|
||||
API_UNAVAILABLE(macCatalyst)
|
||||
@interface OIDExternalUserAgentIOS : NSObject<OIDExternalUserAgent>
|
||||
|
||||
- (nullable instancetype)init API_AVAILABLE(ios(11))
|
||||
__deprecated_msg("This method will not work on iOS 13, use "
|
||||
"initWithPresentingViewController:presentingViewController");
|
||||
|
||||
/*! @brief The designated initializer.
|
||||
@param presentingViewController The view controller from which to present the authentication UI.
|
||||
@discussion The specific authentication UI used depends on the iOS version and accessibility
|
||||
options. iOS 8 uses the system browser, iOS 9-10 use @c SFSafariViewController, iOS 11 uses
|
||||
@c SFAuthenticationSession
|
||||
(unless Guided Access is on which does not work) or uses @c SFSafariViewController, and iOS
|
||||
12+ uses @c ASWebAuthenticationSession (unless Guided Access is on).
|
||||
*/
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Create an external user-agent which optionally uses a private authentication session.
|
||||
@param presentingViewController The view controller from which to present the browser.
|
||||
@param prefersEphemeralSession Whether the caller prefers to use a private authentication
|
||||
session. See @c ASWebAuthenticationSession.prefersEphemeralWebBrowserSession for more.
|
||||
@discussion Authentication is performed with @c ASWebAuthenticationSession (unless Guided Access
|
||||
is on), setting the ephemerality based on the argument.
|
||||
*/
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession
|
||||
API_AVAILABLE(ios(13));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
268
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m
generated
Normal file
268
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOS.m
generated
Normal file
@ -0,0 +1,268 @@
|
||||
/*! @file OIDExternalUserAgentIOS.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import "OIDExternalUserAgentIOS.h"
|
||||
|
||||
#import <SafariServices/SafariServices.h>
|
||||
#import <AuthenticationServices/AuthenticationServices.h>
|
||||
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
@interface OIDExternalUserAgentIOS ()<SFSafariViewControllerDelegate, ASWebAuthenticationPresentationContextProviding>
|
||||
@end
|
||||
#else
|
||||
@interface OIDExternalUserAgentIOS ()<SFSafariViewControllerDelegate>
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation OIDExternalUserAgentIOS {
|
||||
UIViewController *_presentingViewController;
|
||||
BOOL _prefersEphemeralSession;
|
||||
|
||||
BOOL _externalUserAgentFlowInProgress;
|
||||
__weak id<OIDExternalUserAgentSession> _session;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
__weak SFSafariViewController *_safariVC;
|
||||
SFAuthenticationSession *_authenticationVC;
|
||||
ASWebAuthenticationSession *_webAuthenticationVC;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (nullable instancetype)init {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnonnull"
|
||||
return [self initWithPresentingViewController:nil];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
NSAssert(presentingViewController != nil,
|
||||
@"presentingViewController cannot be nil on iOS 13");
|
||||
#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
|
||||
_presentingViewController = presentingViewController;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithPresentingViewController:
|
||||
(UIViewController *)presentingViewController
|
||||
prefersEphemeralSession:(BOOL)prefersEphemeralSession {
|
||||
self = [self initWithPresentingViewController:presentingViewController];
|
||||
if (self) {
|
||||
_prefersEphemeralSession = prefersEphemeralSession;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest>)request
|
||||
session:(id<OIDExternalUserAgentSession>)session {
|
||||
if (_externalUserAgentFlowInProgress) {
|
||||
// TODO: Handle errors as authorization is already in progress.
|
||||
return NO;
|
||||
}
|
||||
|
||||
_externalUserAgentFlowInProgress = YES;
|
||||
_session = session;
|
||||
BOOL openedUserAgent = NO;
|
||||
NSURL *requestURL = [request externalUserAgentRequestURL];
|
||||
|
||||
// iOS 12 and later, use ASWebAuthenticationSession
|
||||
if (@available(iOS 12.0, *)) {
|
||||
// ASWebAuthenticationSession doesn't work with guided access (rdar://40809553)
|
||||
if (!UIAccessibilityIsGuidedAccessEnabled()) {
|
||||
__weak OIDExternalUserAgentIOS *weakSelf = self;
|
||||
NSString *redirectScheme = request.redirectScheme;
|
||||
ASWebAuthenticationSession *authenticationVC =
|
||||
[[ASWebAuthenticationSession alloc] initWithURL:requestURL
|
||||
callbackURLScheme:redirectScheme
|
||||
completionHandler:^(NSURL * _Nullable callbackURL,
|
||||
NSError * _Nullable error) {
|
||||
__strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->_webAuthenticationVC = nil;
|
||||
if (callbackURL) {
|
||||
[strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
|
||||
} else {
|
||||
NSError *safariError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:error
|
||||
description:nil];
|
||||
[strongSelf->_session failExternalUserAgentFlowWithError:safariError];
|
||||
}
|
||||
}];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
if (@available(iOS 13.0, *)) {
|
||||
authenticationVC.presentationContextProvider = self;
|
||||
authenticationVC.prefersEphemeralWebBrowserSession = _prefersEphemeralSession;
|
||||
}
|
||||
#endif
|
||||
_webAuthenticationVC = authenticationVC;
|
||||
openedUserAgent = [authenticationVC start];
|
||||
}
|
||||
}
|
||||
// iOS 11, use SFAuthenticationSession
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// SFAuthenticationSession doesn't work with guided access (rdar://40809553)
|
||||
if (!openedUserAgent && !UIAccessibilityIsGuidedAccessEnabled()) {
|
||||
__weak OIDExternalUserAgentIOS *weakSelf = self;
|
||||
NSString *redirectScheme = request.redirectScheme;
|
||||
SFAuthenticationSession *authenticationVC =
|
||||
[[SFAuthenticationSession alloc] initWithURL:requestURL
|
||||
callbackURLScheme:redirectScheme
|
||||
completionHandler:^(NSURL * _Nullable callbackURL,
|
||||
NSError * _Nullable error) {
|
||||
__strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->_authenticationVC = nil;
|
||||
if (callbackURL) {
|
||||
[strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
|
||||
} else {
|
||||
NSError *safariError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:error
|
||||
description:@"User cancelled."];
|
||||
[strongSelf->_session failExternalUserAgentFlowWithError:safariError];
|
||||
}
|
||||
}];
|
||||
_authenticationVC = authenticationVC;
|
||||
openedUserAgent = [authenticationVC start];
|
||||
}
|
||||
}
|
||||
// iOS 9 and 10, use SFSafariViewController
|
||||
if (@available(iOS 9.0, *)) {
|
||||
if (!openedUserAgent && _presentingViewController) {
|
||||
SFSafariViewController *safariVC =
|
||||
[[SFSafariViewController alloc] initWithURL:requestURL];
|
||||
safariVC.delegate = self;
|
||||
_safariVC = safariVC;
|
||||
[_presentingViewController presentViewController:safariVC animated:YES completion:nil];
|
||||
openedUserAgent = YES;
|
||||
}
|
||||
}
|
||||
// iOS 8 and earlier, use mobile Safari
|
||||
if (!openedUserAgent){
|
||||
openedUserAgent = [[UIApplication sharedApplication] openURL:requestURL];
|
||||
}
|
||||
|
||||
if (!openedUserAgent) {
|
||||
[self cleanUp];
|
||||
NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
|
||||
underlyingError:nil
|
||||
description:@"Unable to open Safari."];
|
||||
[session failExternalUserAgentFlowWithError:safariError];
|
||||
}
|
||||
return openedUserAgent;
|
||||
}
|
||||
|
||||
- (void)dismissExternalUserAgentAnimated:(BOOL)animated completion:(void (^)(void))completion {
|
||||
if (!_externalUserAgentFlowInProgress) {
|
||||
// Ignore this call if there is no authorization flow in progress.
|
||||
if (completion) completion();
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
SFSafariViewController *safariVC = _safariVC;
|
||||
SFAuthenticationSession *authenticationVC = _authenticationVC;
|
||||
ASWebAuthenticationSession *webAuthenticationVC = _webAuthenticationVC;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
[self cleanUp];
|
||||
|
||||
if (webAuthenticationVC) {
|
||||
// dismiss the ASWebAuthenticationSession
|
||||
[webAuthenticationVC cancel];
|
||||
if (completion) completion();
|
||||
} else if (authenticationVC) {
|
||||
// dismiss the SFAuthenticationSession
|
||||
[authenticationVC cancel];
|
||||
if (completion) completion();
|
||||
} else if (safariVC) {
|
||||
// dismiss the SFSafariViewController
|
||||
[safariVC dismissViewControllerAnimated:YES completion:completion];
|
||||
} else {
|
||||
if (completion) completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanUp {
|
||||
// The weak references to |_safariVC| and |_session| are set to nil to avoid accidentally using
|
||||
// them while not in an authorization flow.
|
||||
_safariVC = nil;
|
||||
_authenticationVC = nil;
|
||||
_webAuthenticationVC = nil;
|
||||
_session = nil;
|
||||
_externalUserAgentFlowInProgress = NO;
|
||||
}
|
||||
|
||||
#pragma mark - SFSafariViewControllerDelegate
|
||||
|
||||
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller NS_AVAILABLE_IOS(9.0) {
|
||||
if (controller != _safariVC) {
|
||||
// Ignore this call if the safari view controller do not match.
|
||||
return;
|
||||
}
|
||||
if (!_externalUserAgentFlowInProgress) {
|
||||
// Ignore this call if there is no authorization flow in progress.
|
||||
return;
|
||||
}
|
||||
id<OIDExternalUserAgentSession> session = _session;
|
||||
[self cleanUp];
|
||||
NSError *error = [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:nil
|
||||
description:@"No external user agent flow in progress."];
|
||||
[session failExternalUserAgentFlowWithError:error];
|
||||
}
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
#pragma mark - ASWebAuthenticationPresentationContextProviding
|
||||
|
||||
- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session API_AVAILABLE(ios(13.0)){
|
||||
return _presentingViewController.view.window;
|
||||
}
|
||||
#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // !TARGET_OS_MACCATALYST
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
113
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.h
generated
Normal file
113
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.h
generated
Normal file
@ -0,0 +1,113 @@
|
||||
/*! @file OIDExternalUserAgentIOSCustomBrowser.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2018 Google LLC
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "OIDExternalUserAgent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief A block that transforms a regular http/https URL into one that will open in an
|
||||
alternative browser.
|
||||
@param requestURL the http/https request URL to be transformed.
|
||||
@return transformed URL.
|
||||
*/
|
||||
typedef NSURL *_Nullable (^OIDCustomBrowserURLTransformation)(NSURL *_Nullable requestURL);
|
||||
|
||||
/*! @brief An implementation of the OIDExternalUserAgent protocol for iOS that uses
|
||||
a custom browser (i.e. not Safari) for external requests. It is suitable for browsers that
|
||||
offer a custom url scheme that simply replaces the "https" scheme. It is not designed
|
||||
for browsers that require other modifications to the URL. If the browser is not installed
|
||||
the user will be prompted to install it.
|
||||
*/
|
||||
API_UNAVAILABLE(macCatalyst)
|
||||
@interface OIDExternalUserAgentIOSCustomBrowser : NSObject<OIDExternalUserAgent>
|
||||
|
||||
/*! @brief URL transformation block for the browser.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDCustomBrowserURLTransformation URLTransformation;
|
||||
|
||||
/*! @brief URL Scheme used to test for whether the browser is installed.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *canOpenURLScheme;
|
||||
|
||||
/*! @brief URL of the browser's App Store listing.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *appStoreURL;
|
||||
|
||||
/*! @brief An instance of @c OIDExternalUserAgentIOSCustomBrowser for Chrome.
|
||||
*/
|
||||
+ (instancetype)CustomBrowserChrome;
|
||||
|
||||
/*! @brief An instance of @c OIDExternalUserAgentIOSCustomBrowser for Firefox.
|
||||
*/
|
||||
+ (instancetype)CustomBrowserFirefox;
|
||||
|
||||
/*! @brief An instance of @c OIDExternalUserAgentIOSCustomBrowser for Opera.
|
||||
*/
|
||||
+ (instancetype)CustomBrowserOpera;
|
||||
|
||||
/*! @brief An instance of @c OIDExternalUserAgentIOSCustomBrowser for Safari.
|
||||
*/
|
||||
+ (instancetype)CustomBrowserSafari;
|
||||
|
||||
/*! @brief Creates a @c OIDCustomBrowserURLTransformation using the scheme substitution method used
|
||||
iOS browsers like Chrome and Firefox.
|
||||
*/
|
||||
+ (OIDCustomBrowserURLTransformation)
|
||||
URLTransformationSchemeSubstitutionHTTPS:(NSString *)browserSchemeHTTPS
|
||||
HTTP:(nullable NSString *)browserSchemeHTTP;
|
||||
|
||||
/*! @brief Creates a @c OIDCustomBrowserURLTransformation with the URL prefix method used by
|
||||
iOS browsers like Firefox.
|
||||
*/
|
||||
+ (OIDCustomBrowserURLTransformation) URLTransformationSchemeConcatPrefix:(NSString*)URLprefix;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithURLTransformation:canOpenURLScheme:appStoreURL:
|
||||
*/
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief OIDExternalUserAgent for a custom browser. @c presentExternalUserAgentRequest:session method
|
||||
will return NO if the browser isn't installed.
|
||||
*/
|
||||
- (nullable instancetype)initWithURLTransformation:(OIDCustomBrowserURLTransformation)URLTransformation;
|
||||
|
||||
/*! @brief The designated initializer.
|
||||
@param URLTransformation the transformation block to translate the URL into one that will open
|
||||
in the desired custom browser.
|
||||
@param canOpenURLScheme any scheme supported by the browser used to check if the browser is
|
||||
installed.
|
||||
@param appStoreURL URL of the browser in the app store. When this and @c canOpenURLScheme
|
||||
are non-nil, @c presentExternalUserAgentRequest:session will redirect the user to the app store
|
||||
if the browser is not installed.
|
||||
*/
|
||||
- (nullable instancetype)initWithURLTransformation:(OIDCustomBrowserURLTransformation)URLTransformation
|
||||
canOpenURLScheme:(nullable NSString *)canOpenURLScheme
|
||||
appStoreURL:(nullable NSURL *)appStoreURL
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
171
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.m
generated
Normal file
171
Pods/AppAuth/Source/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.m
generated
Normal file
@ -0,0 +1,171 @@
|
||||
/*! @file OIDExternalUserAgentIOSCustomBrowser.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2018 Google LLC
|
||||
@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 <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
|
||||
#import "OIDExternalUserAgentIOSCustomBrowser.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDAuthorizationService.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDURLQueryComponent.h"
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation OIDExternalUserAgentIOSCustomBrowser
|
||||
|
||||
+ (instancetype)CustomBrowserChrome {
|
||||
// Chrome iOS documentation: https://developer.chrome.com/multidevice/ios/links
|
||||
OIDCustomBrowserURLTransformation transform = [[self class] URLTransformationSchemeSubstitutionHTTPS:@"googlechromes" HTTP:@"googlechrome"];
|
||||
NSURL *appStoreURL =
|
||||
[NSURL URLWithString:@"https://itunes.apple.com/us/app/chrome/id535886823"];
|
||||
return [[[self class] alloc] initWithURLTransformation:transform
|
||||
canOpenURLScheme:@"googlechromes"
|
||||
appStoreURL:appStoreURL];
|
||||
}
|
||||
|
||||
+ (instancetype)CustomBrowserFirefox {
|
||||
// Firefox iOS documentation: https://github.com/mozilla-mobile/firefox-ios-open-in-client
|
||||
OIDCustomBrowserURLTransformation transform =
|
||||
[[self class] URLTransformationSchemeConcatPrefix:@"firefox://open-url?url="];
|
||||
NSURL *appStoreURL =
|
||||
[NSURL URLWithString:@"https://itunes.apple.com/us/app/firefox-web-browser/id989804926"];
|
||||
return [[[self class] alloc] initWithURLTransformation:transform
|
||||
canOpenURLScheme:@"firefox"
|
||||
appStoreURL:appStoreURL];
|
||||
}
|
||||
|
||||
+ (instancetype)CustomBrowserOpera {
|
||||
OIDCustomBrowserURLTransformation transform =
|
||||
[[self class] URLTransformationSchemeSubstitutionHTTPS:@"opera-https" HTTP:@"opera-http"];
|
||||
NSURL *appStoreURL =
|
||||
[NSURL URLWithString:@"https://itunes.apple.com/us/app/opera-mini-web-browser/id363729560"];
|
||||
return [[[self class] alloc] initWithURLTransformation:transform
|
||||
canOpenURLScheme:@"opera-https"
|
||||
appStoreURL:appStoreURL];
|
||||
}
|
||||
|
||||
+ (instancetype)CustomBrowserSafari {
|
||||
OIDCustomBrowserURLTransformation transformNOP = ^NSURL *(NSURL *requestURL) {
|
||||
return requestURL;
|
||||
};
|
||||
OIDExternalUserAgentIOSCustomBrowser *transform =
|
||||
[[[self class] alloc] initWithURLTransformation:transformNOP];
|
||||
return transform;
|
||||
}
|
||||
|
||||
+ (OIDCustomBrowserURLTransformation)
|
||||
URLTransformationSchemeSubstitutionHTTPS:(NSString *)browserSchemeHTTPS
|
||||
HTTP:(nullable NSString *)browserSchemeHTTP {
|
||||
OIDCustomBrowserURLTransformation transform = ^NSURL *(NSURL *requestURL) {
|
||||
// Replace the URL Scheme with the Chrome equivalent.
|
||||
NSString *newScheme = nil;
|
||||
if ([requestURL.scheme isEqualToString:@"https"]) {
|
||||
newScheme = browserSchemeHTTPS;
|
||||
} else if ([requestURL.scheme isEqualToString:@"http"]) {
|
||||
if (!browserSchemeHTTP) {
|
||||
NSAssert(false, @"No HTTP scheme registered for browser");
|
||||
return nil;
|
||||
}
|
||||
newScheme = browserSchemeHTTP;
|
||||
}
|
||||
|
||||
// Replaces the URI scheme with the custom scheme
|
||||
NSURLComponents *components = [NSURLComponents componentsWithURL:requestURL
|
||||
resolvingAgainstBaseURL:YES];
|
||||
components.scheme = newScheme;
|
||||
return components.URL;
|
||||
};
|
||||
return transform;
|
||||
}
|
||||
|
||||
+ (OIDCustomBrowserURLTransformation)URLTransformationSchemeConcatPrefix:(NSString *)URLprefix {
|
||||
OIDCustomBrowserURLTransformation transform = ^NSURL *(NSURL *requestURL) {
|
||||
NSString *requestURLString = [requestURL absoluteString];
|
||||
NSMutableCharacterSet *allowedParamCharacters =
|
||||
[OIDURLQueryComponent URLParamValueAllowedCharacters];
|
||||
NSString *encodedUrl = [requestURLString stringByAddingPercentEncodingWithAllowedCharacters:allowedParamCharacters];
|
||||
NSString *newURL = [NSString stringWithFormat:@"%@%@", URLprefix, encodedUrl];
|
||||
return [NSURL URLWithString:newURL];
|
||||
};
|
||||
return transform;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithURLTransformation:
|
||||
(OIDCustomBrowserURLTransformation)URLTransformation {
|
||||
return [self initWithURLTransformation:URLTransformation canOpenURLScheme:nil appStoreURL:nil];
|
||||
}
|
||||
|
||||
- (nullable instancetype)
|
||||
initWithURLTransformation:(OIDCustomBrowserURLTransformation)URLTransformation
|
||||
canOpenURLScheme:(nullable NSString *)canOpenURLScheme
|
||||
appStoreURL:(nullable NSURL *)appStoreURL {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_URLTransformation = URLTransformation;
|
||||
_canOpenURLScheme = canOpenURLScheme;
|
||||
_appStoreURL = appStoreURL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)presentExternalUserAgentRequest:(nonnull id<OIDExternalUserAgentRequest>)request
|
||||
session:(nonnull id<OIDExternalUserAgentSession>)session {
|
||||
// If the app store URL is set, checks if the app is installed and if not opens the app store.
|
||||
if (_appStoreURL && _canOpenURLScheme) {
|
||||
// Verifies existence of LSApplicationQueriesSchemes Info.plist key.
|
||||
NSArray __unused* canOpenURLs =
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"LSApplicationQueriesSchemes"];
|
||||
NSAssert(canOpenURLs, @"plist missing LSApplicationQueriesSchemes key");
|
||||
NSAssert1([canOpenURLs containsObject:_canOpenURLScheme],
|
||||
@"plist missing LSApplicationQueriesSchemes entry for '%@'", _canOpenURLScheme);
|
||||
|
||||
// Opens AppStore if app isn't installed
|
||||
NSString *testURLString = [NSString stringWithFormat:@"%@://example.com", _canOpenURLScheme];
|
||||
NSURL *testURL = [NSURL URLWithString:testURLString];
|
||||
if (![[UIApplication sharedApplication] canOpenURL:testURL]) {
|
||||
[[UIApplication sharedApplication] openURL:_appStoreURL];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Transforms the request URL and opens it.
|
||||
NSURL *requestURL = [request externalUserAgentRequestURL];
|
||||
requestURL = _URLTransformation(requestURL);
|
||||
BOOL openedInBrowser = [[UIApplication sharedApplication] openURL:requestURL];
|
||||
return openedInBrowser;
|
||||
}
|
||||
|
||||
- (void)dismissExternalUserAgentAnimated:(BOOL)animated
|
||||
completion:(nonnull void (^)(void))completion {
|
||||
completion();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif // !TARGET_OS_MACCATALYST
|
||||
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
|
||||
44
Pods/AppAuth/Source/AppAuthCore.h
generated
Normal file
44
Pods/AppAuth/Source/AppAuthCore.h
generated
Normal file
@ -0,0 +1,44 @@
|
||||
/*! @file AppAuthCore.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthState.h"
|
||||
#import "OIDAuthStateChangeDelegate.h"
|
||||
#import "OIDAuthStateErrorDelegate.h"
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDAuthorizationResponse.h"
|
||||
#import "OIDAuthorizationService.h"
|
||||
#import "OIDError.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDExternalUserAgent.h"
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
#import "OIDGrantTypes.h"
|
||||
#import "OIDIDToken.h"
|
||||
#import "OIDRegistrationRequest.h"
|
||||
#import "OIDRegistrationResponse.h"
|
||||
#import "OIDResponseTypes.h"
|
||||
#import "OIDScopes.h"
|
||||
#import "OIDScopeUtilities.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDServiceDiscovery.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenResponse.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
#import "OIDURLSessionProvider.h"
|
||||
#import "OIDEndSessionRequest.h"
|
||||
#import "OIDEndSessionResponse.h"
|
||||
272
Pods/AppAuth/Source/AppAuthCore/OIDAuthState.h
generated
Normal file
272
Pods/AppAuth/Source/AppAuthCore/OIDAuthState.h
generated
Normal file
@ -0,0 +1,272 @@
|
||||
/*! @file OIDAuthState.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthorizationRequest;
|
||||
@class OIDAuthorizationResponse;
|
||||
@class OIDAuthState;
|
||||
@class OIDRegistrationResponse;
|
||||
@class OIDTokenResponse;
|
||||
@class OIDTokenRequest;
|
||||
@protocol OIDAuthStateChangeDelegate;
|
||||
@protocol OIDAuthStateErrorDelegate;
|
||||
@protocol OIDExternalUserAgent;
|
||||
@protocol OIDExternalUserAgentSession;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents a block used to call an action with a fresh access token.
|
||||
@param accessToken A valid access token if available.
|
||||
@param idToken A valid ID token if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDAuthStateAction)(NSString *_Nullable accessToken,
|
||||
NSString *_Nullable idToken,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief The method called when the @c
|
||||
OIDAuthState.authStateByPresentingAuthorizationRequest:presentingViewController:callback:
|
||||
method has completed or failed.
|
||||
@param authState The auth state, if the authorization request succeeded.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDAuthStateAuthorizationCallback)(OIDAuthState *_Nullable authState,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief A convenience class that retains the auth state between @c OIDAuthorizationResponse%s
|
||||
and @c OIDTokenResponse%s.
|
||||
*/
|
||||
@interface OIDAuthState : NSObject <NSSecureCoding>
|
||||
|
||||
/*! @brief The most recent refresh token received from the server.
|
||||
@discussion Rather than using this property directly, you should call
|
||||
@c OIDAuthState.performActionWithFreshTokens:.
|
||||
@remarks refresh_token
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *refreshToken;
|
||||
|
||||
/*! @brief The scope of the current authorization grant.
|
||||
@discussion This represents the latest scope returned by the server and may be a subset of the
|
||||
scope that was initially granted.
|
||||
@remarks scope
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *scope;
|
||||
|
||||
/*! @brief The most recent authorization response used to update the authorization state. For the
|
||||
implicit flow, this will contain the latest access token.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDAuthorizationResponse *lastAuthorizationResponse;
|
||||
|
||||
/*! @brief The most recent token response used to update this authorization state. This will
|
||||
contain the latest access token.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) OIDTokenResponse *lastTokenResponse;
|
||||
|
||||
/*! @brief The most recent registration response used to update this authorization state. This will
|
||||
contain the latest client credentials.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) OIDRegistrationResponse *lastRegistrationResponse;
|
||||
|
||||
/*! @brief The authorization error that invalidated this @c OIDAuthState.
|
||||
@discussion The authorization error encountered by @c OIDAuthState or set by the user via
|
||||
@c OIDAuthState.updateWithAuthorizationError: that invalidated this @c OIDAuthState.
|
||||
Authorization errors from @c OIDAuthState will always have a domain of
|
||||
@c ::OIDOAuthAuthorizationErrorDomain or @c ::OIDOAuthTokenErrorDomain. Note: that after
|
||||
unarchiving the @c OIDAuthState object, the \NSError_userInfo property of this error will
|
||||
be nil.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSError *authorizationError;
|
||||
|
||||
/*! @brief Returns YES if the authorization state is not known to be invalid.
|
||||
@discussion Returns YES if no OAuth errors have been received, and the last call resulted in a
|
||||
successful access token or id token. This does not mean that the access is fresh - just
|
||||
that it was valid the last time it was used. Note that network and other transient errors
|
||||
do not invalidate the authorized state. If NO, you should authenticate the user again,
|
||||
using a fresh authorization request. Invalid @c OIDAuthState objects may still be useful in
|
||||
that case, to hint at the previously authorized user and streamline the re-authentication
|
||||
experience.
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL isAuthorized;
|
||||
|
||||
/*! @brief The @c OIDAuthStateChangeDelegate delegate.
|
||||
@discussion Use the delegate to observe state changes (and update storage) as well as error
|
||||
states.
|
||||
*/
|
||||
@property(nonatomic, weak, nullable) id<OIDAuthStateChangeDelegate> stateChangeDelegate;
|
||||
|
||||
/*! @brief The @c OIDAuthStateErrorDelegate delegate.
|
||||
@discussion Use the delegate to observe state changes (and update storage) as well as error
|
||||
states.
|
||||
*/
|
||||
@property(nonatomic, weak, nullable) id<OIDAuthStateErrorDelegate> errorDelegate;
|
||||
|
||||
/*! @brief Convenience method to create a @c OIDAuthState by presenting an authorization request
|
||||
and performing the authorization code exchange in the case of code flow requests. For
|
||||
the hybrid flow, the caller should validate the id_token and c_hash, then perform the token
|
||||
request (@c OIDAuthorizationService.performTokenRequest:callback:)
|
||||
and update the OIDAuthState with the results (@c
|
||||
OIDAuthState.updateWithTokenResponse:error:).
|
||||
@param authorizationRequest The authorization request to present.
|
||||
@param externalUserAgent A external user agent that can present an external user-agent request.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithAuthorizationResponse:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Creates an auth state from an authorization response.
|
||||
@param authorizationResponse The authorization response.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse;
|
||||
|
||||
/*! @brief Creates an auth state from an authorization and token response.
|
||||
@param authorizationResponse The authorization response.
|
||||
@param tokenResponse The token response.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse
|
||||
tokenResponse:(nullable OIDTokenResponse *)tokenResponse;
|
||||
|
||||
/*! @brief Creates an auth state from an registration response.
|
||||
@param registrationResponse The registration response.
|
||||
*/
|
||||
- (instancetype)initWithRegistrationResponse:(OIDRegistrationResponse *)registrationResponse;
|
||||
|
||||
/*! @brief Creates an auth state from an authorization, token and registration response.
|
||||
@param authorizationResponse The authorization response.
|
||||
@param tokenResponse The token response.
|
||||
@param registrationResponse The registration response.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationResponse:
|
||||
(nullable OIDAuthorizationResponse *)authorizationResponse
|
||||
tokenResponse:(nullable OIDTokenResponse *)tokenResponse
|
||||
registrationResponse:(nullable OIDRegistrationResponse *)registrationResponse
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Updates the authorization state based on a new authorization response.
|
||||
@param authorizationResponse The new authorization response to update the state with.
|
||||
@param error Any error encountered when performing the authorization request. Errors in the
|
||||
domain @c ::OIDOAuthAuthorizationErrorDomain are reflected in the auth state, other errors
|
||||
are assumed to be transient, and ignored.
|
||||
@discussion Typically called with the response from an incremental authorization request,
|
||||
or if using the implicit flow. Will clear the @c #lastTokenResponse property.
|
||||
*/
|
||||
- (void)updateWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse
|
||||
error:(nullable NSError *)error;
|
||||
|
||||
/*! @brief Updates the authorization state based on a new token response.
|
||||
@param tokenResponse The new token response to update the state from.
|
||||
@param error Any error encountered when performing the authorization request. Errors in the
|
||||
domain @c ::OIDOAuthTokenErrorDomain are reflected in the auth state, other errors
|
||||
are assumed to be transient, and ignored.
|
||||
@discussion Typically called with the response from an authorization code exchange, or a token
|
||||
refresh.
|
||||
*/
|
||||
- (void)updateWithTokenResponse:(nullable OIDTokenResponse *)tokenResponse
|
||||
error:(nullable NSError *)error;
|
||||
|
||||
/*! @brief Updates the authorization state based on a new registration response.
|
||||
@param registrationResponse The new registration response to update the state with.
|
||||
@discussion Typically called with the response from a successful client registration
|
||||
request. Will reset the auth state.
|
||||
*/
|
||||
- (void)updateWithRegistrationResponse:(nullable OIDRegistrationResponse *)registrationResponse;
|
||||
|
||||
/*! @brief Updates the authorization state based on an authorization error.
|
||||
@param authorizationError The authorization error.
|
||||
@discussion Call this method if you receive an authorization error during an API call to
|
||||
invalidate the authentication state of this @c OIDAuthState. Don't call with errors
|
||||
unrelated to authorization, such as transient network errors.
|
||||
The OIDAuthStateErrorDelegate.authState:didEncounterAuthorizationError: method of
|
||||
@c #errorDelegate will be called with the error.
|
||||
You may optionally use the convenience method
|
||||
OIDErrorUtilities.resourceServerAuthorizationErrorWithCode:errorResponse:underlyingError:
|
||||
to create \NSError objects for use here.
|
||||
The latest error received is stored in @c #authorizationError. Note: that after unarchiving
|
||||
this object, the \NSError_userInfo property of this error will be nil.
|
||||
*/
|
||||
- (void)updateWithAuthorizationError:(NSError *)authorizationError;
|
||||
|
||||
/*! @brief Calls the block with a valid access token (refreshing it first, if needed), or if a
|
||||
refresh was needed and failed, with the error that caused it to fail.
|
||||
@param action The block to execute with a fresh token. This block will be executed on the main
|
||||
thread.
|
||||
*/
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action;
|
||||
|
||||
/*! @brief Calls the block with a valid access token (refreshing it first, if needed), or if a
|
||||
refresh was needed and failed, with the error that caused it to fail.
|
||||
@param action The block to execute with a fresh token. This block will be executed on the main
|
||||
thread.
|
||||
@param additionalParameters Additional parameters for the token request if token is
|
||||
refreshed.
|
||||
*/
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action
|
||||
additionalRefreshParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Calls the block with a valid access token (refreshing it first, if needed), or if a
|
||||
refresh was needed and failed, with the error that caused it to fail.
|
||||
@param action The block to execute with a fresh token. This block will be executed on the main
|
||||
thread.
|
||||
@param additionalParameters Additional parameters for the token request if token is
|
||||
refreshed.
|
||||
@param dispatchQueue The dispatchQueue on which to dispatch the action block.
|
||||
*/
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action
|
||||
additionalRefreshParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
dispatchQueue:(dispatch_queue_t)dispatchQueue;
|
||||
|
||||
/*! @brief Forces a token refresh the next time @c OIDAuthState.performActionWithFreshTokens: is
|
||||
called, even if the current tokens are considered valid.
|
||||
*/
|
||||
- (void)setNeedsTokenRefresh;
|
||||
|
||||
/*! @brief Creates a token request suitable for refreshing an access token.
|
||||
@return A @c OIDTokenRequest suitable for using a refresh token to obtain a new access token.
|
||||
@discussion After performing the refresh, call @c OIDAuthState.updateWithTokenResponse:error:
|
||||
to update the authorization state based on the response. Rather than doing the token refresh
|
||||
yourself, you should use @c OIDAuthState.performActionWithFreshTokens:.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-1.5
|
||||
*/
|
||||
- (nullable OIDTokenRequest *)tokenRefreshRequest;
|
||||
|
||||
/*! @brief Creates a token request suitable for refreshing an access token.
|
||||
@param additionalParameters Additional parameters for the token request.
|
||||
@return A @c OIDTokenRequest suitable for using a refresh token to obtain a new access token.
|
||||
@discussion After performing the refresh, call @c OIDAuthState.updateWithTokenResponse:error:
|
||||
to update the authorization state based on the response. Rather than doing the token refresh
|
||||
yourself, you should use @c OIDAuthState.performActionWithFreshTokens:.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-1.5
|
||||
*/
|
||||
- (nullable OIDTokenRequest *)tokenRefreshRequestWithAdditionalParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
570
Pods/AppAuth/Source/AppAuthCore/OIDAuthState.m
generated
Normal file
570
Pods/AppAuth/Source/AppAuthCore/OIDAuthState.m
generated
Normal file
@ -0,0 +1,570 @@
|
||||
/*! @file OIDAuthState.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthState.h"
|
||||
|
||||
#import "OIDAuthStateChangeDelegate.h"
|
||||
#import "OIDAuthStateErrorDelegate.h"
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDAuthorizationResponse.h"
|
||||
#import "OIDAuthorizationService.h"
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDError.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDRegistrationResponse.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenResponse.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
|
||||
/*! @brief Key used to encode the @c refreshToken property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kRefreshTokenKey = @"refreshToken";
|
||||
|
||||
/*! @brief Key used to encode the @c needsTokenRefresh property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kNeedsTokenRefreshKey = @"needsTokenRefresh";
|
||||
|
||||
/*! @brief Key used to encode the @c scope property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kScopeKey = @"scope";
|
||||
|
||||
/*! @brief Key used to encode the @c lastAuthorizationResponse property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kLastAuthorizationResponseKey = @"lastAuthorizationResponse";
|
||||
|
||||
/*! @brief Key used to encode the @c lastTokenResponse property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kLastTokenResponseKey = @"lastTokenResponse";
|
||||
|
||||
/*! @brief Key used to encode the @c lastOAuthError property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kAuthorizationErrorKey = @"authorizationError";
|
||||
|
||||
/*! @brief The exception thrown when a developer tries to create a refresh request from an
|
||||
authorization request with no authorization code.
|
||||
*/
|
||||
static NSString *const kRefreshTokenRequestException =
|
||||
@"Attempted to create a token refresh request from a token response with no refresh token.";
|
||||
|
||||
/*! @brief Number of seconds the access token is refreshed before it actually expires.
|
||||
*/
|
||||
static const NSUInteger kExpiryTimeTolerance = 60;
|
||||
|
||||
/*! @brief Object to hold OIDAuthState pending actions.
|
||||
*/
|
||||
@interface OIDAuthStatePendingAction : NSObject
|
||||
@property(nonatomic, readonly, nullable) OIDAuthStateAction action;
|
||||
@property(nonatomic, readonly, nullable) dispatch_queue_t dispatchQueue;
|
||||
@end
|
||||
@implementation OIDAuthStatePendingAction
|
||||
- (id)initWithAction:(OIDAuthStateAction)action andDispatchQueue:(dispatch_queue_t)dispatchQueue {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_action = action;
|
||||
_dispatchQueue = dispatchQueue;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface OIDAuthState ()
|
||||
|
||||
/*! @brief The access token generated by the authorization server.
|
||||
@discussion Rather than using this property directly, you should call
|
||||
@c OIDAuthState.withFreshTokenPerformAction:.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *accessToken;
|
||||
|
||||
/*! @brief The approximate expiration date & time of the access token.
|
||||
@discussion Rather than using this property directly, you should call
|
||||
@c OIDAuthState.withFreshTokenPerformAction:.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDate *accessTokenExpirationDate;
|
||||
|
||||
/*! @brief ID Token value associated with the authenticated session.
|
||||
@discussion Rather than using this property directly, you should call
|
||||
OIDAuthState.withFreshTokenPerformAction:.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *idToken;
|
||||
|
||||
/*! @brief Private method, called when the internal state changes.
|
||||
*/
|
||||
- (void)didChangeState;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OIDAuthState {
|
||||
/*! @brief Array of pending actions (use @c _pendingActionsSyncObject to synchronize access).
|
||||
*/
|
||||
NSMutableArray *_pendingActions;
|
||||
|
||||
/*! @brief Object for synchronizing access to @c pendingActions.
|
||||
*/
|
||||
id _pendingActionsSyncObject;
|
||||
|
||||
/*! @brief If YES, tokens will be refreshed on the next API call regardless of expiry.
|
||||
*/
|
||||
BOOL _needsTokenRefresh;
|
||||
}
|
||||
|
||||
#pragma mark - Convenience initializers
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
authStateByPresentingAuthorizationRequest:(OIDAuthorizationRequest *)authorizationRequest
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDAuthStateAuthorizationCallback)callback {
|
||||
// presents the authorization request
|
||||
id<OIDExternalUserAgentSession> authFlowSession = [OIDAuthorizationService
|
||||
presentAuthorizationRequest:authorizationRequest
|
||||
externalUserAgent:externalUserAgent
|
||||
callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse,
|
||||
NSError *_Nullable authorizationError) {
|
||||
// inspects response and processes further if needed (e.g. authorization
|
||||
// code exchange)
|
||||
if (authorizationResponse) {
|
||||
if ([authorizationRequest.responseType
|
||||
isEqualToString:OIDResponseTypeCode]) {
|
||||
// if the request is for the code flow (NB. not hybrid), assumes the
|
||||
// code is intended for this client, and performs the authorization
|
||||
// code exchange
|
||||
OIDTokenRequest *tokenExchangeRequest =
|
||||
[authorizationResponse tokenExchangeRequest];
|
||||
[OIDAuthorizationService performTokenRequest:tokenExchangeRequest
|
||||
originalAuthorizationResponse:authorizationResponse
|
||||
callback:^(OIDTokenResponse *_Nullable tokenResponse,
|
||||
NSError *_Nullable tokenError) {
|
||||
OIDAuthState *authState;
|
||||
if (tokenResponse) {
|
||||
authState = [[OIDAuthState alloc]
|
||||
initWithAuthorizationResponse:
|
||||
authorizationResponse
|
||||
tokenResponse:tokenResponse];
|
||||
}
|
||||
callback(authState, tokenError);
|
||||
}];
|
||||
} else {
|
||||
// hybrid flow (code id_token). Two possible cases:
|
||||
// 1. The code is not for this client, ie. will be sent to a
|
||||
// webservice that performs the id token verification and token
|
||||
// exchange
|
||||
// 2. The code is for this client and, for security reasons, the
|
||||
// application developer must verify the id_token signature and
|
||||
// c_hash before calling the token endpoint
|
||||
OIDAuthState *authState = [[OIDAuthState alloc]
|
||||
initWithAuthorizationResponse:authorizationResponse];
|
||||
callback(authState, authorizationError);
|
||||
}
|
||||
} else {
|
||||
callback(nil, authorizationError);
|
||||
}
|
||||
}];
|
||||
return authFlowSession;
|
||||
}
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (nonnull instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithAuthorizationResponse:tokenResponse:))
|
||||
|
||||
/*! @brief Creates an auth state from an authorization response.
|
||||
@param authorizationResponse The authorization response.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse {
|
||||
return [self initWithAuthorizationResponse:authorizationResponse tokenResponse:nil];
|
||||
}
|
||||
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param authorizationResponse The authorization response.
|
||||
@discussion Creates an auth state from an authorization response and token response.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationResponse:(OIDAuthorizationResponse *)authorizationResponse
|
||||
tokenResponse:(nullable OIDTokenResponse *)tokenResponse {
|
||||
return [self initWithAuthorizationResponse:authorizationResponse
|
||||
tokenResponse:tokenResponse
|
||||
registrationResponse:nil];
|
||||
}
|
||||
|
||||
/*! @brief Creates an auth state from an registration response.
|
||||
@param registrationResponse The registration response.
|
||||
*/
|
||||
- (instancetype)initWithRegistrationResponse:(OIDRegistrationResponse *)registrationResponse {
|
||||
return [self initWithAuthorizationResponse:nil
|
||||
tokenResponse:nil
|
||||
registrationResponse:registrationResponse];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationResponse:
|
||||
(nullable OIDAuthorizationResponse *)authorizationResponse
|
||||
tokenResponse:(nullable OIDTokenResponse *)tokenResponse
|
||||
registrationResponse:(nullable OIDRegistrationResponse *)registrationResponse {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_pendingActionsSyncObject = [[NSObject alloc] init];
|
||||
|
||||
if (registrationResponse) {
|
||||
[self updateWithRegistrationResponse:registrationResponse];
|
||||
}
|
||||
|
||||
if (authorizationResponse) {
|
||||
[self updateWithAuthorizationResponse:authorizationResponse error:nil];
|
||||
}
|
||||
|
||||
if (tokenResponse) {
|
||||
[self updateWithTokenResponse:tokenResponse error:nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, isAuthorized: %@, refreshToken: \"%@\", "
|
||||
"scope: \"%@\", accessToken: \"%@\", "
|
||||
"accessTokenExpirationDate: %@, idToken: \"%@\", "
|
||||
"lastAuthorizationResponse: %@, lastTokenResponse: %@, "
|
||||
"lastRegistrationResponse: %@, authorizationError: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
(self.isAuthorized) ? @"YES" : @"NO",
|
||||
[OIDTokenUtilities redact:_refreshToken],
|
||||
_scope,
|
||||
[OIDTokenUtilities redact:self.accessToken],
|
||||
self.accessTokenExpirationDate,
|
||||
[OIDTokenUtilities redact:self.idToken],
|
||||
_lastAuthorizationResponse,
|
||||
_lastTokenResponse,
|
||||
_lastRegistrationResponse,
|
||||
_authorizationError];
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
_lastAuthorizationResponse = [aDecoder decodeObjectOfClass:[OIDAuthorizationResponse class]
|
||||
forKey:kLastAuthorizationResponseKey];
|
||||
_lastTokenResponse = [aDecoder decodeObjectOfClass:[OIDTokenResponse class]
|
||||
forKey:kLastTokenResponseKey];
|
||||
self = [self initWithAuthorizationResponse:_lastAuthorizationResponse
|
||||
tokenResponse:_lastTokenResponse];
|
||||
if (self) {
|
||||
_authorizationError =
|
||||
[aDecoder decodeObjectOfClass:[NSError class] forKey:kAuthorizationErrorKey];
|
||||
_scope = [aDecoder decodeObjectOfClass:[NSString class] forKey:kScopeKey];
|
||||
_refreshToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kRefreshTokenKey];
|
||||
_needsTokenRefresh = [aDecoder decodeBoolForKey:kNeedsTokenRefreshKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_lastAuthorizationResponse forKey:kLastAuthorizationResponseKey];
|
||||
[aCoder encodeObject:_lastTokenResponse forKey:kLastTokenResponseKey];
|
||||
if (_authorizationError) {
|
||||
NSError *codingSafeAuthorizationError = [NSError errorWithDomain:_authorizationError.domain
|
||||
code:_authorizationError.code
|
||||
userInfo:nil];
|
||||
[aCoder encodeObject:codingSafeAuthorizationError forKey:kAuthorizationErrorKey];
|
||||
}
|
||||
[aCoder encodeObject:_scope forKey:kScopeKey];
|
||||
[aCoder encodeObject:_refreshToken forKey:kRefreshTokenKey];
|
||||
[aCoder encodeBool:_needsTokenRefresh forKey:kNeedsTokenRefreshKey];
|
||||
}
|
||||
|
||||
#pragma mark - Private convenience getters
|
||||
|
||||
- (NSString *)accessToken {
|
||||
if (_authorizationError) {
|
||||
return nil;
|
||||
}
|
||||
return _lastTokenResponse ? _lastTokenResponse.accessToken
|
||||
: _lastAuthorizationResponse.accessToken;
|
||||
}
|
||||
|
||||
- (NSString *)tokenType {
|
||||
if (_authorizationError) {
|
||||
return nil;
|
||||
}
|
||||
return _lastTokenResponse ? _lastTokenResponse.tokenType
|
||||
: _lastAuthorizationResponse.tokenType;
|
||||
}
|
||||
|
||||
- (NSDate *)accessTokenExpirationDate {
|
||||
if (_authorizationError) {
|
||||
return nil;
|
||||
}
|
||||
return _lastTokenResponse ? _lastTokenResponse.accessTokenExpirationDate
|
||||
: _lastAuthorizationResponse.accessTokenExpirationDate;
|
||||
}
|
||||
|
||||
- (NSString *)idToken {
|
||||
if (_authorizationError) {
|
||||
return nil;
|
||||
}
|
||||
return _lastTokenResponse ? _lastTokenResponse.idToken
|
||||
: _lastAuthorizationResponse.idToken;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (BOOL)isAuthorized {
|
||||
return !self.authorizationError && (self.accessToken || self.idToken || self.refreshToken);
|
||||
}
|
||||
|
||||
#pragma mark - Updating the state
|
||||
|
||||
- (void)updateWithRegistrationResponse:(OIDRegistrationResponse *)registrationResponse {
|
||||
_lastRegistrationResponse = registrationResponse;
|
||||
_refreshToken = nil;
|
||||
_scope = nil;
|
||||
_lastAuthorizationResponse = nil;
|
||||
_lastTokenResponse = nil;
|
||||
_authorizationError = nil;
|
||||
[self didChangeState];
|
||||
}
|
||||
|
||||
- (void)updateWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse
|
||||
error:(nullable NSError *)error {
|
||||
// If the error is an OAuth authorization error, updates the state. Other errors are ignored.
|
||||
if (error.domain == OIDOAuthAuthorizationErrorDomain) {
|
||||
[self updateWithAuthorizationError:error];
|
||||
return;
|
||||
}
|
||||
if (!authorizationResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastAuthorizationResponse = authorizationResponse;
|
||||
|
||||
// clears the last token response and refresh token as these now relate to an old authorization
|
||||
// that is no longer relevant
|
||||
_lastTokenResponse = nil;
|
||||
_refreshToken = nil;
|
||||
_authorizationError = nil;
|
||||
|
||||
// if the response's scope is nil, it means that it equals that of the request
|
||||
// see: https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
_scope = (authorizationResponse.scope) ? authorizationResponse.scope
|
||||
: authorizationResponse.request.scope;
|
||||
|
||||
[self didChangeState];
|
||||
}
|
||||
|
||||
- (void)updateWithTokenResponse:(nullable OIDTokenResponse *)tokenResponse
|
||||
error:(nullable NSError *)error {
|
||||
if (_authorizationError) {
|
||||
// Calling updateWithTokenResponse while in an error state probably means the developer obtained
|
||||
// a new token and did the exchange without also calling updateWithAuthorizationResponse.
|
||||
// Attempts to handle gracefully, but warns the developer that this is unexpected.
|
||||
NSLog(@"OIDAuthState:updateWithTokenResponse should not be called in an error state [%@] call"
|
||||
"updateWithAuthorizationResponse with the result of the fresh authorization response"
|
||||
"first",
|
||||
_authorizationError);
|
||||
|
||||
_authorizationError = nil;
|
||||
}
|
||||
|
||||
// If the error is an OAuth authorization error, updates the state. Other errors are ignored.
|
||||
if (error.domain == OIDOAuthTokenErrorDomain) {
|
||||
[self updateWithAuthorizationError:error];
|
||||
return;
|
||||
}
|
||||
if (!tokenResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastTokenResponse = tokenResponse;
|
||||
|
||||
// updates the scope and refresh token if they are present on the TokenResponse.
|
||||
// according to the spec, these may be changed by the server, including when refreshing the
|
||||
// access token. See: https://tools.ietf.org/html/rfc6749#section-5.1 and
|
||||
// https://tools.ietf.org/html/rfc6749#section-6
|
||||
if (tokenResponse.scope) {
|
||||
_scope = tokenResponse.scope;
|
||||
}
|
||||
if (tokenResponse.refreshToken) {
|
||||
_refreshToken = tokenResponse.refreshToken;
|
||||
}
|
||||
|
||||
[self didChangeState];
|
||||
}
|
||||
|
||||
- (void)updateWithAuthorizationError:(NSError *)oauthError {
|
||||
_authorizationError = oauthError;
|
||||
|
||||
[self didChangeState];
|
||||
|
||||
[_errorDelegate authState:self didEncounterAuthorizationError:oauthError];
|
||||
}
|
||||
|
||||
#pragma mark - OAuth Requests
|
||||
|
||||
- (OIDTokenRequest *)tokenRefreshRequest {
|
||||
return [self tokenRefreshRequestWithAdditionalParameters:nil];
|
||||
}
|
||||
|
||||
- (OIDTokenRequest *)tokenRefreshRequestWithAdditionalParameters:
|
||||
(NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
|
||||
// TODO: Add unit test to confirm exception is thrown when expected
|
||||
|
||||
if (!_refreshToken) {
|
||||
[OIDErrorUtilities raiseException:kRefreshTokenRequestException];
|
||||
}
|
||||
return [[OIDTokenRequest alloc]
|
||||
initWithConfiguration:_lastAuthorizationResponse.request.configuration
|
||||
grantType:OIDGrantTypeRefreshToken
|
||||
authorizationCode:nil
|
||||
redirectURL:nil
|
||||
clientID:_lastAuthorizationResponse.request.clientID
|
||||
clientSecret:_lastAuthorizationResponse.request.clientSecret
|
||||
scope:nil
|
||||
refreshToken:_refreshToken
|
||||
codeVerifier:nil
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
#pragma mark - Stateful Actions
|
||||
|
||||
- (void)didChangeState {
|
||||
[_stateChangeDelegate didChangeState:self];
|
||||
}
|
||||
|
||||
- (void)setNeedsTokenRefresh {
|
||||
_needsTokenRefresh = YES;
|
||||
}
|
||||
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action {
|
||||
[self performActionWithFreshTokens:action additionalRefreshParameters:nil];
|
||||
}
|
||||
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action
|
||||
additionalRefreshParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
[self performActionWithFreshTokens:action
|
||||
additionalRefreshParameters:additionalParameters
|
||||
dispatchQueue:dispatch_get_main_queue()];
|
||||
}
|
||||
|
||||
- (void)performActionWithFreshTokens:(OIDAuthStateAction)action
|
||||
additionalRefreshParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
dispatchQueue:(dispatch_queue_t)dispatchQueue {
|
||||
|
||||
if ([self isTokenFresh]) {
|
||||
// access token is valid within tolerance levels, perform action
|
||||
dispatch_async(dispatchQueue, ^{
|
||||
action(self.accessToken, self.idToken, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_refreshToken) {
|
||||
// no refresh token available and token has expired
|
||||
NSError *tokenRefreshError = [
|
||||
OIDErrorUtilities errorWithCode:OIDErrorCodeTokenRefreshError
|
||||
underlyingError:nil
|
||||
description:@"Unable to refresh expired token without a refresh token."];
|
||||
dispatch_async(dispatchQueue, ^{
|
||||
action(nil, nil, tokenRefreshError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// access token is expired, first refresh the token, then perform action
|
||||
NSAssert(_pendingActionsSyncObject, @"_pendingActionsSyncObject cannot be nil", @"");
|
||||
OIDAuthStatePendingAction* pendingAction =
|
||||
[[OIDAuthStatePendingAction alloc] initWithAction:action andDispatchQueue:dispatchQueue];
|
||||
@synchronized(_pendingActionsSyncObject) {
|
||||
// if a token is already in the process of being refreshed, adds to pending actions
|
||||
if (_pendingActions) {
|
||||
[_pendingActions addObject:pendingAction];
|
||||
return;
|
||||
}
|
||||
|
||||
// creates a list of pending actions, starting with this one
|
||||
_pendingActions = [NSMutableArray arrayWithObject:pendingAction];
|
||||
}
|
||||
|
||||
// refresh the tokens
|
||||
OIDTokenRequest *tokenRefreshRequest =
|
||||
[self tokenRefreshRequestWithAdditionalParameters:additionalParameters];
|
||||
[OIDAuthorizationService performTokenRequest:tokenRefreshRequest
|
||||
originalAuthorizationResponse:_lastAuthorizationResponse
|
||||
callback:^(OIDTokenResponse *_Nullable response,
|
||||
NSError *_Nullable error) {
|
||||
// update OIDAuthState based on response
|
||||
if (response) {
|
||||
self->_needsTokenRefresh = NO;
|
||||
[self updateWithTokenResponse:response error:nil];
|
||||
} else {
|
||||
if (error.domain == OIDOAuthTokenErrorDomain) {
|
||||
self->_needsTokenRefresh = NO;
|
||||
[self updateWithAuthorizationError:error];
|
||||
} else {
|
||||
if ([self->_errorDelegate respondsToSelector:
|
||||
@selector(authState:didEncounterTransientError:)]) {
|
||||
[self->_errorDelegate authState:self didEncounterTransientError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nil the pending queue and process everything that was queued up
|
||||
NSArray *actionsToProcess;
|
||||
@synchronized(self->_pendingActionsSyncObject) {
|
||||
actionsToProcess = self->_pendingActions;
|
||||
self->_pendingActions = nil;
|
||||
}
|
||||
for (OIDAuthStatePendingAction* actionToProcess in actionsToProcess) {
|
||||
dispatch_async(actionToProcess.dispatchQueue, ^{
|
||||
actionToProcess.action(self.accessToken, self.idToken, error);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*! @fn isTokenFresh
|
||||
@brief Determines whether a token refresh request must be made to refresh the tokens.
|
||||
*/
|
||||
- (BOOL)isTokenFresh {
|
||||
if (_needsTokenRefresh) {
|
||||
// forced refresh
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!self.accessTokenExpirationDate) {
|
||||
// if there is no expiration time but we have an access token, it is assumed to never expire
|
||||
return !!self.accessToken;
|
||||
}
|
||||
|
||||
// has the token expired?
|
||||
BOOL tokenFresh = [self.accessTokenExpirationDate timeIntervalSinceNow] > kExpiryTimeTolerance;
|
||||
return tokenFresh;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
39
Pods/AppAuth/Source/AppAuthCore/OIDAuthStateChangeDelegate.h
generated
Normal file
39
Pods/AppAuth/Source/AppAuthCore/OIDAuthStateChangeDelegate.h
generated
Normal file
@ -0,0 +1,39 @@
|
||||
/*! @file OIDAuthStateChangeDelegate.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthState;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @protocol OIDAuthStateChangeDelegate
|
||||
@brief Delegate of the OIDAuthState used to monitor various changes in state.
|
||||
*/
|
||||
@protocol OIDAuthStateChangeDelegate <NSObject>
|
||||
|
||||
/*! @brief Called when the authorization state changes and any backing storage needs to be updated.
|
||||
@param state The @c OIDAuthState that changed.
|
||||
@discussion If you are storing the authorization state, you should update the storage when the
|
||||
state changes.
|
||||
*/
|
||||
- (void)didChangeState:(OIDAuthState *)state;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
62
Pods/AppAuth/Source/AppAuthCore/OIDAuthStateErrorDelegate.h
generated
Normal file
62
Pods/AppAuth/Source/AppAuthCore/OIDAuthStateErrorDelegate.h
generated
Normal file
@ -0,0 +1,62 @@
|
||||
/*! @file OIDAuthStateErrorDelegate.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthState;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @protocol OIDAuthStateErrorDelegate
|
||||
@brief Delegate of the OIDAuthState used to monitor errors.
|
||||
*/
|
||||
@protocol OIDAuthStateErrorDelegate <NSObject>
|
||||
|
||||
/*! @brief Called when an authentication occurs, which indicates the auth session is invalid.
|
||||
@param state The @c OIDAuthState on which the error occurred.
|
||||
@param error The authorization error.
|
||||
@discussion This is a hard error (not a transient network issue) that indicates a problem with
|
||||
the authorization. You should stop using the @c OIDAuthState when such an error is
|
||||
encountered. If the \NSError_code is @c ::OIDErrorCodeOAuthInvalidGrant then
|
||||
the session may be recoverable with user interaction (i.e. re-authentication). In all cases
|
||||
you should consider the user unauthorized, and remove locally cached resources that require
|
||||
that authorization. @c OIDAuthState will call this method automatically if it encounters
|
||||
an OAuth error (that is, an HTTP 400 response with a valid OAuth error response) during
|
||||
authorization or token refresh (such as performed automatically when using
|
||||
@c OIDAuthState.performActionWithFreshTokens:). You can signal authorization errors with
|
||||
@c OIDAuthState.updateWithAuthorizationError:.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
- (void)authState:(OIDAuthState *)state didEncounterAuthorizationError:(NSError *)error;
|
||||
|
||||
@optional
|
||||
|
||||
/*! @brief Called when a network or other transient error occurs.
|
||||
@param state The @c OIDAuthState on which the error occurred.
|
||||
@param error The transient error.
|
||||
@discussion This is a soft error, typically network related. The @c OIDAuthState is likely
|
||||
still valid, and should not be discarded. Retry the request using an incremental backoff
|
||||
strategy. This is only called when using the @c OIDAuthState convenience methods such as
|
||||
@c OIDAuthState.performActionWithFreshTokens:. If you are refreshing the tokens yourself
|
||||
outside of @c OIDAuthState class, it will never be called.
|
||||
*/
|
||||
- (void)authState:(OIDAuthState *)state didEncounterTransientError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
250
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationRequest.h
generated
Normal file
250
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationRequest.h
generated
Normal file
@ -0,0 +1,250 @@
|
||||
/*! @file OIDAuthorizationRequest.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
// These files only declare string constants useful for constructing a @c OIDAuthorizationRequest,
|
||||
// so they are imported here for convenience.
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
#import "OIDResponseTypes.h"
|
||||
#import "OIDScopes.h"
|
||||
|
||||
@class OIDServiceConfiguration;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief The @c code_challenge_method value for the S256 code challenge.
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.3
|
||||
*/
|
||||
extern NSString *const OIDOAuthorizationRequestCodeChallengeMethodS256;
|
||||
|
||||
|
||||
/*! @brief Represents an authorization request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
*/
|
||||
@interface OIDAuthorizationRequest :
|
||||
NSObject<NSCopying, NSSecureCoding, OIDExternalUserAgentRequest>
|
||||
|
||||
/*! @brief The service's configuration.
|
||||
@remarks This configuration specifies how to connect to a particular OAuth provider.
|
||||
Configurations may be created manually, or via an OpenID Connect Discovery Document.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDServiceConfiguration *configuration;
|
||||
|
||||
/*! @brief The expected response type.
|
||||
@remarks response_type
|
||||
@discussion Generally 'code' if pure OAuth, otherwise a space-delimited list of of response
|
||||
types including 'code', 'token', and 'id_token' for OpenID Connect.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.1.1
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *responseType;
|
||||
|
||||
/*! @brief The client identifier.
|
||||
@remarks client_id
|
||||
@see https://tools.ietf.org/html/rfc6749#section-2.2
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *clientID;
|
||||
|
||||
/*! @brief The client secret.
|
||||
@remarks client_secret
|
||||
@discussion The client secret is used to prove that identity of the client when exchaning an
|
||||
authorization code for an access token.
|
||||
The client secret is not passed in the authorizationRequestURL. It is only used when
|
||||
exchanging the authorization code for an access token.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *clientSecret;
|
||||
|
||||
/*! @brief The value of the scope parameter is expressed as a list of space-delimited,
|
||||
case-sensitive strings.
|
||||
@remarks scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *scope;
|
||||
|
||||
/*! @brief The client's redirect URI.
|
||||
@remarks redirect_uri
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *redirectURL;
|
||||
|
||||
/*! @brief An opaque value used by the client to maintain state between the request and callback.
|
||||
@remarks state
|
||||
@discussion If this value is not explicitly set, this library will automatically add state and
|
||||
perform appropriate validation of the state in the authorization response. It is recommended
|
||||
that the default implementation of this parameter be used wherever possible. Typically used
|
||||
to prevent CSRF attacks, as recommended in RFC6819 Section 5.3.5.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
@see https://tools.ietf.org/html/rfc6819#section-5.3.5
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *state;
|
||||
|
||||
/*! @brief String value used to associate a Client session with an ID Token, and to mitigate replay
|
||||
attacks. The value is passed through unmodified from the Authentication Request to the ID
|
||||
Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from
|
||||
guessing values.
|
||||
@remarks nonce
|
||||
@discussion If this value is not explicitly set, this library will automatically add nonce and
|
||||
perform appropriate validation of the nonce in the ID Token.
|
||||
@see https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *nonce;
|
||||
|
||||
/*! @brief The PKCE code verifier.
|
||||
@remarks code_verifier
|
||||
@discussion The code verifier itself is not included in the authorization request that is sent
|
||||
on the wire, but needs to be in the token exchange request.
|
||||
@c OIDAuthorizationResponse.tokenExchangeRequest will create a @c OIDTokenRequest that
|
||||
includes this parameter automatically.
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *codeVerifier;
|
||||
|
||||
/*! @brief The PKCE code challenge, derived from #codeVerifier.
|
||||
@remarks code_challenge
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.2
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *codeChallenge;
|
||||
|
||||
/*! @brief The method used to compute the @c #codeChallenge
|
||||
@remarks code_challenge_method
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *codeChallengeMethod;
|
||||
|
||||
/*! @brief The client's additional authorization parameters.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use
|
||||
@c initWithConfiguration:clientId:scopes:redirectURL:responseType:additionalParameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Creates an authorization request with opinionated defaults (a secure @c state, and
|
||||
PKCE with S256 as the @c code_challenge_method).
|
||||
@param configuration The service's configuration.
|
||||
@param clientID The client identifier.
|
||||
@param scopes An array of scopes to combine into a single scope string per the OAuth2 spec.
|
||||
@param redirectURL The client's redirect URI.
|
||||
@param responseType The expected response type.
|
||||
@param additionalParameters The client's additional authorization parameters.
|
||||
@remarks This convenience initializer generates a state parameter and PKCE challenges
|
||||
automatically.
|
||||
*/
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
redirectURL:(NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Creates an authorization request with opinionated defaults (a secure @c state, @c nonce,
|
||||
and PKCE with S256 as the @c code_challenge_method).
|
||||
@param configuration The service's configuration.
|
||||
@param clientID The client identifier.
|
||||
@param clientSecret The client secret.
|
||||
@param scopes An array of scopes to combine into a single scope string per the OAuth2 spec.
|
||||
@param redirectURL The client's redirect URI.
|
||||
@param responseType The expected response type.
|
||||
@param additionalParameters The client's additional authorization parameters.
|
||||
@remarks This convenience initializer generates a state parameter and PKCE challenges
|
||||
automatically.
|
||||
*/
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
redirectURL:(NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param configuration The service's configuration.
|
||||
@param clientID The client identifier.
|
||||
@param scope A scope string per the OAuth2 spec (a space-delimited set of scopes).
|
||||
@param redirectURL The client's redirect URI.
|
||||
@param responseType The expected response type.
|
||||
@param state An opaque value used by the client to maintain state between the request and
|
||||
callback.
|
||||
@param nonce String value used to associate a Client session with an ID Token. Can be set to nil
|
||||
if not using OpenID Connect, although pure OAuth servers should ignore params they don't
|
||||
understand anyway.
|
||||
@param codeVerifier The PKCE code verifier. See @c OIDAuthorizationRequest.generateCodeVerifier.
|
||||
@param codeChallenge The PKCE code challenge, calculated from the code verifier such as with
|
||||
@c OIDAuthorizationRequest.codeChallengeS256ForVerifier:.
|
||||
@param codeChallengeMethod The PKCE code challenge method.
|
||||
::OIDOAuthorizationRequestCodeChallengeMethodS256 when
|
||||
@c OIDAuthorizationRequest.codeChallengeS256ForVerifier: is used to create the code
|
||||
challenge.
|
||||
@param additionalParameters The client's additional authorization parameters.
|
||||
*/
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scope:(nullable NSString *)scope
|
||||
redirectURL:(nullable NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
state:(nullable NSString *)state
|
||||
nonce:(nullable NSString *)nonce
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
codeChallenge:(nullable NSString *)codeChallenge
|
||||
codeChallengeMethod:(nullable NSString *)codeChallengeMethod
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Constructs the request URI by adding the request parameters to the query component of the
|
||||
authorization endpoint URI using the "application/x-www-form-urlencoded" format.
|
||||
@return A URL representing the authorization request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
*/
|
||||
- (NSURL *)authorizationRequestURL;
|
||||
|
||||
/*! @brief Generates an OAuth state param using a random source.
|
||||
@return The generated state.
|
||||
@see https://tools.ietf.org/html/rfc6819#section-5.3.5
|
||||
*/
|
||||
+ (nullable NSString *)generateState;
|
||||
|
||||
/*! @brief Constructs a PKCE-compliant code verifier.
|
||||
@return The generated code verifier.
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.1
|
||||
*/
|
||||
+ (nullable NSString *)generateCodeVerifier;
|
||||
|
||||
/*! @brief Creates a PKCE S256 codeChallenge from the codeVerifier.
|
||||
@param codeVerifier The code verifier from which the code challenge will be derived.
|
||||
@return The generated code challenge.
|
||||
@details Generate a secure code verifier to pass into this method with
|
||||
@c OIDAuthorizationRequest.generateCodeVerifier. The matching @c #codeChallengeMethod for
|
||||
@c #codeChallenge%s created by this method is
|
||||
::OIDOAuthorizationRequestCodeChallengeMethodS256.
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.1
|
||||
*/
|
||||
+ (nullable NSString *)codeChallengeS256ForVerifier:(nullable NSString *)codeVerifier;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
351
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationRequest.m
generated
Normal file
351
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationRequest.m
generated
Normal file
@ -0,0 +1,351 @@
|
||||
/*! @file OIDAuthorizationRequest.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthorizationRequest.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDScopeUtilities.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
#import "OIDURLQueryComponent.h"
|
||||
|
||||
/*! @brief The key for the @c configuration property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kConfigurationKey = @"configuration";
|
||||
|
||||
/*! @brief Key used to encode the @c responseType property for @c NSSecureCoding, and on the URL
|
||||
request.
|
||||
*/
|
||||
static NSString *const kResponseTypeKey = @"response_type";
|
||||
|
||||
/*! @brief Key used to encode the @c clientID property for @c NSSecureCoding, and on the URL
|
||||
request.
|
||||
*/
|
||||
static NSString *const kClientIDKey = @"client_id";
|
||||
|
||||
/*! @brief Key used to encode the @c clientSecret property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kClientSecretKey = @"client_secret";
|
||||
|
||||
/*! @brief Key used to encode the @c scope property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kScopeKey = @"scope";
|
||||
|
||||
/*! @brief Key used to encode the @c redirectURL property for @c NSSecureCoding, and on the URL
|
||||
request.
|
||||
*/
|
||||
static NSString *const kRedirectURLKey = @"redirect_uri";
|
||||
|
||||
/*! @brief Key used to encode the @c state property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kStateKey = @"state";
|
||||
|
||||
/*! @brief Key used to encode the @c nonce property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kNonceKey = @"nonce";
|
||||
|
||||
/*! @brief Key used to encode the @c codeVerifier property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kCodeVerifierKey = @"code_verifier";
|
||||
|
||||
/*! @brief Key used to send the @c codeChallenge on the URL request.
|
||||
*/
|
||||
static NSString *const kCodeChallengeKey = @"code_challenge";
|
||||
|
||||
/*! @brief Key used to send the @c codeChallengeMethod on the URL request.
|
||||
*/
|
||||
static NSString *const kCodeChallengeMethodKey = @"code_challenge_method";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for
|
||||
@c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
/*! @brief Number of random bytes generated for the @ state.
|
||||
*/
|
||||
static NSUInteger const kStateSizeBytes = 32;
|
||||
|
||||
/*! @brief Number of random bytes generated for the @ codeVerifier.
|
||||
*/
|
||||
static NSUInteger const kCodeVerifierBytes = 32;
|
||||
|
||||
/*! @brief Assertion text for unsupported response types.
|
||||
*/
|
||||
static NSString *const OIDOAuthUnsupportedResponseTypeMessage =
|
||||
@"The response_type \"%@\" isn't supported. AppAuth only supports the \"code\" or \"code id_token\" response_type.";
|
||||
|
||||
/*! @brief Code challenge request method.
|
||||
*/
|
||||
NSString *const OIDOAuthorizationRequestCodeChallengeMethodS256 = @"S256";
|
||||
|
||||
@implementation OIDAuthorizationRequest
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(
|
||||
@selector(initWithConfiguration:
|
||||
clientId:
|
||||
scopes:
|
||||
redirectURL:
|
||||
responseType:
|
||||
additionalParameters:)
|
||||
)
|
||||
|
||||
/*! @brief Check if the response type is one AppAuth supports
|
||||
@remarks AppAuth only supports the `code` and `code id_token` response types.
|
||||
@see https://github.com/openid/AppAuth-iOS/issues/98
|
||||
@see https://github.com/openid/AppAuth-iOS/issues/292
|
||||
*/
|
||||
+ (BOOL)isSupportedResponseType:(NSString *)responseType
|
||||
{
|
||||
NSString *codeIdToken = [@[OIDResponseTypeCode, OIDResponseTypeIDToken]
|
||||
componentsJoinedByString:@" "];
|
||||
NSString *idTokenCode = [@[OIDResponseTypeIDToken, OIDResponseTypeCode]
|
||||
componentsJoinedByString:@" "];
|
||||
|
||||
return [responseType isEqualToString:OIDResponseTypeCode]
|
||||
|| [responseType isEqualToString:codeIdToken]
|
||||
|| [responseType isEqualToString:idTokenCode];
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scope:(nullable NSString *)scope
|
||||
redirectURL:(NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
state:(nullable NSString *)state
|
||||
nonce:(nullable NSString *)nonce
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
codeChallenge:(nullable NSString *)codeChallenge
|
||||
codeChallengeMethod:(nullable NSString *)codeChallengeMethod
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configuration = [configuration copy];
|
||||
_clientID = [clientID copy];
|
||||
_clientSecret = [clientSecret copy];
|
||||
_scope = [scope copy];
|
||||
_redirectURL = [redirectURL copy];
|
||||
_responseType = [responseType copy];
|
||||
if (![[self class] isSupportedResponseType:_responseType]) {
|
||||
NSAssert(NO, OIDOAuthUnsupportedResponseTypeMessage, _responseType);
|
||||
return nil;
|
||||
}
|
||||
_state = [state copy];
|
||||
_nonce = [nonce copy];
|
||||
_codeVerifier = [codeVerifier copy];
|
||||
_codeChallenge = [codeChallenge copy];
|
||||
_codeChallengeMethod = [codeChallengeMethod copy];
|
||||
|
||||
_additionalParameters =
|
||||
[[NSDictionary alloc] initWithDictionary:additionalParameters copyItems:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
clientSecret:(NSString *)clientSecret
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
redirectURL:(NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
|
||||
// generates PKCE code verifier and challenge
|
||||
NSString *codeVerifier = [[self class] generateCodeVerifier];
|
||||
NSString *codeChallenge = [[self class] codeChallengeS256ForVerifier:codeVerifier];
|
||||
|
||||
return [self initWithConfiguration:configuration
|
||||
clientId:clientID
|
||||
clientSecret:clientSecret
|
||||
scope:[OIDScopeUtilities scopesWithArray:scopes]
|
||||
redirectURL:redirectURL
|
||||
responseType:responseType
|
||||
state:[[self class] generateState]
|
||||
nonce:[[self class] generateState]
|
||||
codeVerifier:codeVerifier
|
||||
codeChallenge:codeChallenge
|
||||
codeChallengeMethod:OIDOAuthorizationRequestCodeChallengeMethodS256
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
clientId:(NSString *)clientID
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
redirectURL:(NSURL *)redirectURL
|
||||
responseType:(NSString *)responseType
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
return [self initWithConfiguration:configuration
|
||||
clientId:clientID
|
||||
clientSecret:nil
|
||||
scopes:scopes
|
||||
redirectURL:redirectURL
|
||||
responseType:responseType
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDServiceConfiguration *configuration =
|
||||
[aDecoder decodeObjectOfClass:[OIDServiceConfiguration class]
|
||||
forKey:kConfigurationKey];
|
||||
NSString *responseType = [aDecoder decodeObjectOfClass:[NSString class] forKey:kResponseTypeKey];
|
||||
NSString *clientID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kClientIDKey];
|
||||
NSString *clientSecret = [aDecoder decodeObjectOfClass:[NSString class] forKey:kClientSecretKey];
|
||||
NSString *scope = [aDecoder decodeObjectOfClass:[NSString class] forKey:kScopeKey];
|
||||
NSURL *redirectURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kRedirectURLKey];
|
||||
NSString *state = [aDecoder decodeObjectOfClass:[NSString class] forKey:kStateKey];
|
||||
NSString *nonce = [aDecoder decodeObjectOfClass:[NSString class] forKey:kNonceKey];
|
||||
NSString *codeVerifier = [aDecoder decodeObjectOfClass:[NSString class] forKey:kCodeVerifierKey];
|
||||
NSString *codeChallenge =
|
||||
[aDecoder decodeObjectOfClass:[NSString class] forKey:kCodeChallengeKey];
|
||||
NSString *codeChallengeMethod =
|
||||
[aDecoder decodeObjectOfClass:[NSString class] forKey:kCodeChallengeMethodKey];
|
||||
NSSet *additionalParameterCodingClasses = [NSSet setWithArray:@[
|
||||
[NSDictionary class],
|
||||
[NSString class]
|
||||
]];
|
||||
NSDictionary *additionalParameters =
|
||||
[aDecoder decodeObjectOfClasses:additionalParameterCodingClasses
|
||||
forKey:kAdditionalParametersKey];
|
||||
|
||||
self = [self initWithConfiguration:configuration
|
||||
clientId:clientID
|
||||
clientSecret:clientSecret
|
||||
scope:scope
|
||||
redirectURL:redirectURL
|
||||
responseType:responseType
|
||||
state:state
|
||||
nonce:nonce
|
||||
codeVerifier:codeVerifier
|
||||
codeChallenge:codeChallenge
|
||||
codeChallengeMethod:codeChallengeMethod
|
||||
additionalParameters:additionalParameters];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_configuration forKey:kConfigurationKey];
|
||||
[aCoder encodeObject:_responseType forKey:kResponseTypeKey];
|
||||
[aCoder encodeObject:_clientID forKey:kClientIDKey];
|
||||
[aCoder encodeObject:_clientSecret forKey:kClientSecretKey];
|
||||
[aCoder encodeObject:_scope forKey:kScopeKey];
|
||||
[aCoder encodeObject:_redirectURL forKey:kRedirectURLKey];
|
||||
[aCoder encodeObject:_state forKey:kStateKey];
|
||||
[aCoder encodeObject:_nonce forKey:kNonceKey];
|
||||
[aCoder encodeObject:_codeVerifier forKey:kCodeVerifierKey];
|
||||
[aCoder encodeObject:_codeChallenge forKey:kCodeChallengeKey];
|
||||
[aCoder encodeObject:_codeChallengeMethod forKey:kCodeChallengeMethodKey];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
self.authorizationRequestURL];
|
||||
}
|
||||
|
||||
#pragma mark - State and PKCE verifier/challenge generation Methods
|
||||
|
||||
+ (nullable NSString *)generateCodeVerifier {
|
||||
return [OIDTokenUtilities randomURLSafeStringWithSize:kCodeVerifierBytes];
|
||||
}
|
||||
|
||||
+ (nullable NSString *)generateState {
|
||||
return [OIDTokenUtilities randomURLSafeStringWithSize:kStateSizeBytes];
|
||||
}
|
||||
|
||||
+ (nullable NSString *)codeChallengeS256ForVerifier:(NSString *)codeVerifier {
|
||||
if (!codeVerifier) {
|
||||
return nil;
|
||||
}
|
||||
// generates the code_challenge per spec https://tools.ietf.org/html/rfc7636#section-4.2
|
||||
// code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
|
||||
// NB. the ASCII conversion on the code_verifier entropy was done at time of generation.
|
||||
NSData *sha256Verifier = [OIDTokenUtilities sha256:codeVerifier];
|
||||
return [OIDTokenUtilities encodeBase64urlNoPadding:sha256Verifier];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSURL *)authorizationRequestURL {
|
||||
OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] init];
|
||||
|
||||
// Required parameters.
|
||||
[query addParameter:kResponseTypeKey value:_responseType];
|
||||
[query addParameter:kClientIDKey value:_clientID];
|
||||
|
||||
// Add any additional parameters the client has specified.
|
||||
[query addParameters:_additionalParameters];
|
||||
|
||||
// Add optional parameters, as applicable.
|
||||
if (_redirectURL) {
|
||||
[query addParameter:kRedirectURLKey value:_redirectURL.absoluteString];
|
||||
}
|
||||
if (_scope) {
|
||||
[query addParameter:kScopeKey value:_scope];
|
||||
}
|
||||
if (_state) {
|
||||
[query addParameter:kStateKey value:_state];
|
||||
}
|
||||
if (_nonce) {
|
||||
[query addParameter:kNonceKey value:_nonce];
|
||||
}
|
||||
if (_codeChallenge) {
|
||||
[query addParameter:kCodeChallengeKey value:_codeChallenge];
|
||||
}
|
||||
if (_codeChallengeMethod) {
|
||||
[query addParameter:kCodeChallengeMethodKey value:_codeChallengeMethod];
|
||||
}
|
||||
|
||||
// Construct the URL:
|
||||
return [query URLByReplacingQueryInURL:_configuration.authorizationEndpoint];
|
||||
}
|
||||
|
||||
#pragma mark - OIDExternalUserAgentRequest
|
||||
|
||||
- (NSURL *)externalUserAgentRequestURL {
|
||||
return [self authorizationRequestURL];
|
||||
}
|
||||
|
||||
- (NSString *)redirectScheme {
|
||||
return [[self redirectURL] scheme];
|
||||
}
|
||||
|
||||
@end
|
||||
128
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationResponse.h
generated
Normal file
128
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationResponse.h
generated
Normal file
@ -0,0 +1,128 @@
|
||||
/*! @file OIDAuthorizationResponse.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthorizationRequest;
|
||||
@class OIDTokenRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents the response to an authorization request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
|
||||
*/
|
||||
@interface OIDAuthorizationResponse : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The request which was serviced.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDAuthorizationRequest *request;
|
||||
|
||||
/*! @brief The authorization code generated by the authorization server.
|
||||
@discussion Set when the response_type requested includes 'code'.
|
||||
@remarks code
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *authorizationCode;
|
||||
|
||||
/*! @brief REQUIRED if the "state" parameter was present in the client authorization request. The
|
||||
exact value received from the client.
|
||||
@remarks state
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *state;
|
||||
|
||||
/*! @brief The access token generated by the authorization server.
|
||||
@discussion Set when the response_type requested includes 'token'.
|
||||
@remarks access_token
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *accessToken;
|
||||
|
||||
/*! @brief The approximate expiration date & time of the access token.
|
||||
@discussion Set when the response_type requested includes 'token'.
|
||||
@remarks expires_in
|
||||
@seealso OIDAuthorizationResponse.accessToken
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDate *accessTokenExpirationDate;
|
||||
|
||||
/*! @brief Typically "Bearer" when present. Otherwise, another token_type value that the Client has
|
||||
negotiated with the Authorization Server.
|
||||
@discussion Set when the response_type requested includes 'token'.
|
||||
@remarks token_type
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *tokenType;
|
||||
|
||||
/*! @brief ID Token value associated with the authenticated session.
|
||||
@discussion Set when the response_type requested includes 'id_token'.
|
||||
@remarks id_token
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *idToken;
|
||||
|
||||
/*! @brief The scope of the access token. OPTIONAL, if identical to the scopes requested, otherwise,
|
||||
REQUIRED.
|
||||
@remarks scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *scope;
|
||||
|
||||
/*! @brief Additional parameters returned from the authorization server.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithRequest:parameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param request The serviced request.
|
||||
@param parameters The decoded parameters returned from the Authorization Server.
|
||||
@remarks Known parameters are extracted from the @c parameters parameter and the normative
|
||||
properties are populated. Non-normative parameters are placed in the
|
||||
@c #additionalParameters dictionary.
|
||||
*/
|
||||
- (instancetype)initWithRequest:(OIDAuthorizationRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Creates a token request suitable for exchanging an authorization code for an access
|
||||
token.
|
||||
@return A @c OIDTokenRequest suitable for exchanging an authorization code for an access
|
||||
token.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
- (nullable OIDTokenRequest *)tokenExchangeRequest;
|
||||
|
||||
/*! @brief Creates a token request suitable for exchanging an authorization code for an access
|
||||
token.
|
||||
@param additionalParameters Additional parameters for the token request.
|
||||
@return A @c OIDTokenRequest suitable for exchanging an authorization code for an access
|
||||
token.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
- (nullable OIDTokenRequest *)tokenExchangeRequestWithAdditionalParameters:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
210
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationResponse.m
generated
Normal file
210
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationResponse.m
generated
Normal file
@ -0,0 +1,210 @@
|
||||
/*! @file OIDAuthorizationResponse.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthorizationResponse.h"
|
||||
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDError.h"
|
||||
#import "OIDFieldMapping.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
|
||||
/*! @brief The key for the @c authorizationCode property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kAuthorizationCodeKey = @"code";
|
||||
|
||||
/*! @brief The key for the @c state property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kStateKey = @"state";
|
||||
|
||||
/*! @brief The key for the @c accessToken property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kAccessTokenKey = @"access_token";
|
||||
|
||||
/*! @brief The key for the @c accessTokenExpirationDate property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kExpiresInKey = @"expires_in";
|
||||
|
||||
/*! @brief The key for the @c tokenType property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kTokenTypeKey = @"token_type";
|
||||
|
||||
/*! @brief The key for the @c idToken property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kIDTokenKey = @"id_token";
|
||||
|
||||
/*! @brief The key for the @c scope property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kScopeKey = @"scope";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
/*! @brief Key used to encode the @c request property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRequestKey = @"request";
|
||||
|
||||
/*! @brief The exception thrown when a developer tries to create a token exchange request from an
|
||||
authorization request with no authorization code.
|
||||
*/
|
||||
static NSString *const kTokenExchangeRequestException =
|
||||
@"Attempted to create a token exchange request from an authorization response with no "
|
||||
"authorization code.";
|
||||
|
||||
@implementation OIDAuthorizationResponse
|
||||
|
||||
/*! @brief Returns a mapping of incoming parameters to instance variables.
|
||||
@return A mapping of incoming parameters to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, OIDFieldMapping *> *)fieldMap {
|
||||
static NSMutableDictionary<NSString *, OIDFieldMapping *> *fieldMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
fieldMap = [NSMutableDictionary dictionary];
|
||||
fieldMap[kStateKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_state" type:[NSString class]];
|
||||
fieldMap[kAuthorizationCodeKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_authorizationCode" type:[NSString class]];
|
||||
fieldMap[kAccessTokenKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_accessToken" type:[NSString class]];
|
||||
fieldMap[kExpiresInKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_accessTokenExpirationDate"
|
||||
type:[NSDate class]
|
||||
conversion:^id _Nullable(NSObject *_Nullable value) {
|
||||
if (![value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
NSNumber *valueAsNumber = (NSNumber *)value;
|
||||
return [NSDate dateWithTimeIntervalSinceNow:[valueAsNumber longLongValue]];
|
||||
}];
|
||||
fieldMap[kTokenTypeKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_tokenType" type:[NSString class]];
|
||||
fieldMap[kIDTokenKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_idToken" type:[NSString class]];
|
||||
fieldMap[kScopeKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_scope" type:[NSString class]];
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithRequest:parameters:))
|
||||
|
||||
- (instancetype)initWithRequest:(OIDAuthorizationRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters =
|
||||
[OIDFieldMapping remainingParametersWithMap:[[self class] fieldMap]
|
||||
parameters:parameters
|
||||
instance:self];
|
||||
_additionalParameters = additionalParameters;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDAuthorizationRequest *request =
|
||||
[aDecoder decodeObjectOfClass:[OIDAuthorizationRequest class] forKey:kRequestKey];
|
||||
self = [self initWithRequest:request parameters:@{ }];
|
||||
if (self) {
|
||||
[OIDFieldMapping decodeWithCoder:aDecoder map:[[self class] fieldMap] instance:self];
|
||||
_additionalParameters = [aDecoder decodeObjectOfClasses:[OIDFieldMapping JSONTypes]
|
||||
forKey:kAdditionalParametersKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_request forKey:kRequestKey];
|
||||
[OIDFieldMapping encodeWithCoder:aCoder map:[[self class] fieldMap] instance:self];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, authorizationCode: %@, state: \"%@\", accessToken: "
|
||||
"\"%@\", accessTokenExpirationDate: %@, tokenType: %@, "
|
||||
"idToken: \"%@\", scope: \"%@\", additionalParameters: %@, "
|
||||
"request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
_authorizationCode,
|
||||
_state,
|
||||
[OIDTokenUtilities redact:_accessToken],
|
||||
_accessTokenExpirationDate,
|
||||
_tokenType,
|
||||
[OIDTokenUtilities redact:_idToken],
|
||||
_scope,
|
||||
_additionalParameters,
|
||||
_request];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (OIDTokenRequest *)tokenExchangeRequest {
|
||||
return [self tokenExchangeRequestWithAdditionalParameters:nil];
|
||||
}
|
||||
|
||||
- (OIDTokenRequest *)tokenExchangeRequestWithAdditionalParameters:
|
||||
(NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
// TODO: add a unit test to confirm exception is thrown when expected and the request is created
|
||||
// with the correct parameters.
|
||||
if (!_authorizationCode) {
|
||||
[NSException raise:kTokenExchangeRequestException
|
||||
format:kTokenExchangeRequestException];
|
||||
}
|
||||
return [[OIDTokenRequest alloc] initWithConfiguration:_request.configuration
|
||||
grantType:OIDGrantTypeAuthorizationCode
|
||||
authorizationCode:_authorizationCode
|
||||
redirectURL:_request.redirectURL
|
||||
clientID:_request.clientID
|
||||
clientSecret:_request.clientSecret
|
||||
scope:nil
|
||||
refreshToken:nil
|
||||
codeVerifier:_request.codeVerifier
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
@end
|
||||
170
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationService.h
generated
Normal file
170
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationService.h
generated
Normal file
@ -0,0 +1,170 @@
|
||||
/*! @file OIDAuthorizationService.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthorization;
|
||||
@class OIDAuthorizationRequest;
|
||||
@class OIDAuthorizationResponse;
|
||||
@class OIDEndSessionRequest;
|
||||
@class OIDEndSessionResponse;
|
||||
@class OIDRegistrationRequest;
|
||||
@class OIDRegistrationResponse;
|
||||
@class OIDServiceConfiguration;
|
||||
@class OIDTokenRequest;
|
||||
@class OIDTokenResponse;
|
||||
@protocol OIDExternalUserAgent;
|
||||
@protocol OIDExternalUserAgentSession;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents the type of block used as a callback for creating a service configuration from
|
||||
a remote OpenID Connect Discovery document.
|
||||
@param configuration The service configuration, if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDDiscoveryCallback)(OIDServiceConfiguration *_Nullable configuration,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Represents the type of block used as a callback for various methods of
|
||||
@c OIDAuthorizationService.
|
||||
@param authorizationResponse The authorization response, if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDAuthorizationCallback)(OIDAuthorizationResponse *_Nullable authorizationResponse,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Block used as a callback for the end-session request of @c OIDAuthorizationService.
|
||||
@param endSessionResponse The end-session response, if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDEndSessionCallback)(OIDEndSessionResponse *_Nullable endSessionResponse,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Represents the type of block used as a callback for various methods of
|
||||
@c OIDAuthorizationService.
|
||||
@param tokenResponse The token response, if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDTokenCallback)(OIDTokenResponse *_Nullable tokenResponse,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Represents the type of dictionary used to specify additional querystring parameters
|
||||
when making authorization or token endpoint requests.
|
||||
*/
|
||||
typedef NSDictionary<NSString *, NSString *> *_Nullable OIDTokenEndpointParameters;
|
||||
|
||||
/*! @brief Represents the type of block used as a callback for various methods of
|
||||
@c OIDAuthorizationService.
|
||||
@param registrationResponse The registration response, if available.
|
||||
@param error The error if an error occurred.
|
||||
*/
|
||||
typedef void (^OIDRegistrationCompletion)(OIDRegistrationResponse *_Nullable registrationResponse,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Performs various OAuth and OpenID Connect related calls via the user agent or
|
||||
\NSURLSession.
|
||||
*/
|
||||
@interface OIDAuthorizationService : NSObject
|
||||
|
||||
/*! @brief The service's configuration.
|
||||
@remarks Each authorization service is initialized with a configuration. This configuration
|
||||
specifies how to connect to a particular OAuth provider. Clients should use separate
|
||||
authorization service instances for each provider they wish to integrate with.
|
||||
Configurations may be created manually, or via an OpenID Connect Discovery Document.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDServiceConfiguration *configuration;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. This class should not be initialized.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Convenience method for creating an authorization service configuration from an OpenID
|
||||
Connect compliant issuer URL.
|
||||
@param issuerURL The service provider's OpenID Connect issuer.
|
||||
@param completion A block which will be invoked when the authorization service configuration has
|
||||
been created, or when an error has occurred.
|
||||
@see https://openid.net/specs/openid-connect-discovery-1_0.html
|
||||
*/
|
||||
+ (void)discoverServiceConfigurationForIssuer:(NSURL *)issuerURL
|
||||
completion:(OIDDiscoveryCallback)completion;
|
||||
|
||||
|
||||
/*! @brief Convenience method for creating an authorization service configuration from an OpenID
|
||||
Connect compliant identity provider's discovery document.
|
||||
@param discoveryURL The URL of the service provider's OpenID Connect discovery document.
|
||||
@param completion A block which will be invoked when the authorization service configuration has
|
||||
been created, or when an error has occurred.
|
||||
@see https://openid.net/specs/openid-connect-discovery-1_0.html
|
||||
*/
|
||||
+ (void)discoverServiceConfigurationForDiscoveryURL:(NSURL *)discoveryURL
|
||||
completion:(OIDDiscoveryCallback)completion;
|
||||
|
||||
/*! @brief Perform an authorization flow using a generic flow shim.
|
||||
@param request The authorization request.
|
||||
@param externalUserAgent Generic external user-agent that can present an authorization
|
||||
request.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDAuthorizationCallback)callback;
|
||||
|
||||
/*! @brief Perform a logout request.
|
||||
@param request The end-session logout request.
|
||||
@param externalUserAgent Generic external user-agent that can present user-agent requests.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
@return A @c OIDExternalUserAgentSession instance which will terminate when it
|
||||
receives a @c OIDExternalUserAgentSession.cancel message, or after processing a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
presentEndSessionRequest:(OIDEndSessionRequest *)request
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDEndSessionCallback)callback;
|
||||
|
||||
/*! @brief Performs a token request.
|
||||
@param request The token request.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
*/
|
||||
+ (void)performTokenRequest:(OIDTokenRequest *)request callback:(OIDTokenCallback)callback;
|
||||
|
||||
/*! @brief Performs a token request.
|
||||
@param request The token request.
|
||||
@param authorizationResponse The original authorization response related to this token request.
|
||||
@param callback The method called when the request has completed or failed.
|
||||
*/
|
||||
+ (void)performTokenRequest:(OIDTokenRequest *)request
|
||||
originalAuthorizationResponse:(OIDAuthorizationResponse *_Nullable)authorizationResponse
|
||||
callback:(OIDTokenCallback)callback;
|
||||
|
||||
/*! @brief Performs a registration request.
|
||||
@param request The registration request.
|
||||
@param completion The method called when the request has completed or failed.
|
||||
*/
|
||||
+ (void)performRegistrationRequest:(OIDRegistrationRequest *)request
|
||||
completion:(OIDRegistrationCompletion)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
790
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationService.m
generated
Normal file
790
Pods/AppAuth/Source/AppAuthCore/OIDAuthorizationService.m
generated
Normal file
@ -0,0 +1,790 @@
|
||||
/*! @file OIDAuthorizationService.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDAuthorizationService.h"
|
||||
|
||||
#import "OIDAuthorizationRequest.h"
|
||||
#import "OIDAuthorizationResponse.h"
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDEndSessionRequest.h"
|
||||
#import "OIDEndSessionResponse.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDExternalUserAgent.h"
|
||||
#import "OIDExternalUserAgentSession.h"
|
||||
#import "OIDIDToken.h"
|
||||
#import "OIDRegistrationRequest.h"
|
||||
#import "OIDRegistrationResponse.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDServiceDiscovery.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenResponse.h"
|
||||
#import "OIDURLQueryComponent.h"
|
||||
#import "OIDURLSessionProvider.h"
|
||||
|
||||
/*! @brief Path appended to an OpenID Connect issuer for discovery
|
||||
@see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
|
||||
*/
|
||||
static NSString *const kOpenIDConfigurationWellKnownPath = @".well-known/openid-configuration";
|
||||
|
||||
/*! @brief Max allowable iat (Issued At) time skew
|
||||
@see https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
*/
|
||||
static int const kOIDAuthorizationSessionIATMaxSkew = 600;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OIDAuthorizationSession : NSObject<OIDExternalUserAgentSession>
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithRequest:(OIDAuthorizationRequest *)request
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OIDAuthorizationSession {
|
||||
OIDAuthorizationRequest *_request;
|
||||
id<OIDExternalUserAgent> _externalUserAgent;
|
||||
OIDAuthorizationCallback _pendingauthorizationFlowCallback;
|
||||
}
|
||||
|
||||
- (instancetype)initWithRequest:(OIDAuthorizationRequest *)request {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)presentAuthorizationWithExternalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDAuthorizationCallback)authorizationFlowCallback {
|
||||
_externalUserAgent = externalUserAgent;
|
||||
_pendingauthorizationFlowCallback = authorizationFlowCallback;
|
||||
BOOL authorizationFlowStarted =
|
||||
[_externalUserAgent presentExternalUserAgentRequest:_request session:self];
|
||||
if (!authorizationFlowStarted) {
|
||||
NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
|
||||
underlyingError:nil
|
||||
description:@"Unable to open Safari."];
|
||||
[self didFinishWithResponse:nil error:safariError];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
[self cancelWithCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)cancelWithCompletion:(nullable void (^)(void))completion {
|
||||
[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
|
||||
NSError *error = [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:nil
|
||||
description:@"Authorization flow was cancelled."];
|
||||
[self didFinishWithResponse:nil error:error];
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
|
||||
/*! @brief Does the redirection URL equal another URL down to the path component?
|
||||
@param URL The first redirect URI to compare.
|
||||
@param redirectionURL The second redirect URI to compare.
|
||||
@return YES if the URLs match down to the path level (query params are ignored).
|
||||
*/
|
||||
+ (BOOL)URL:(NSURL *)URL matchesRedirectionURL:(NSURL *)redirectionURL {
|
||||
NSURL *standardizedURL = [URL standardizedURL];
|
||||
NSURL *standardizedRedirectURL = [redirectionURL standardizedURL];
|
||||
|
||||
return [standardizedURL.scheme caseInsensitiveCompare:standardizedRedirectURL.scheme] == NSOrderedSame
|
||||
&& OIDIsEqualIncludingNil(standardizedURL.user, standardizedRedirectURL.user)
|
||||
&& OIDIsEqualIncludingNil(standardizedURL.password, standardizedRedirectURL.password)
|
||||
&& OIDIsEqualIncludingNil(standardizedURL.host, standardizedRedirectURL.host)
|
||||
&& OIDIsEqualIncludingNil(standardizedURL.port, standardizedRedirectURL.port)
|
||||
&& OIDIsEqualIncludingNil(standardizedURL.path, standardizedRedirectURL.path);
|
||||
}
|
||||
|
||||
- (BOOL)shouldHandleURL:(NSURL *)URL {
|
||||
return [[self class] URL:URL matchesRedirectionURL:_request.redirectURL];
|
||||
}
|
||||
|
||||
- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL {
|
||||
// rejects URLs that don't match redirect (these may be completely unrelated to the authorization)
|
||||
if (![self shouldHandleURL:URL]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
AppAuthRequestTrace(@"Authorization Response: %@", URL);
|
||||
|
||||
// checks for an invalid state
|
||||
if (!_pendingauthorizationFlowCallback) {
|
||||
[NSException raise:OIDOAuthExceptionInvalidAuthorizationFlow
|
||||
format:@"%@", OIDOAuthExceptionInvalidAuthorizationFlow, nil];
|
||||
}
|
||||
|
||||
OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] initWithURL:URL];
|
||||
|
||||
NSError *error;
|
||||
OIDAuthorizationResponse *response = nil;
|
||||
|
||||
// checks for an OAuth error response as per RFC6749 Section 4.1.2.1
|
||||
if (query.dictionaryValue[OIDOAuthErrorFieldError]) {
|
||||
error = [OIDErrorUtilities OAuthErrorWithDomain:OIDOAuthAuthorizationErrorDomain
|
||||
OAuthResponse:query.dictionaryValue
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
// no error, should be a valid OAuth 2.0 response
|
||||
if (!error) {
|
||||
response = [[OIDAuthorizationResponse alloc] initWithRequest:_request
|
||||
parameters:query.dictionaryValue];
|
||||
|
||||
// verifies that the state in the response matches the state in the request, or both are nil
|
||||
if (!OIDIsEqualIncludingNil(_request.state, response.state)) {
|
||||
NSMutableDictionary *userInfo = [query.dictionaryValue mutableCopy];
|
||||
userInfo[NSLocalizedDescriptionKey] =
|
||||
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
|
||||
"response %@",
|
||||
_request.state,
|
||||
response.state,
|
||||
response];
|
||||
response = nil;
|
||||
error = [NSError errorWithDomain:OIDOAuthAuthorizationErrorDomain
|
||||
code:OIDErrorCodeOAuthAuthorizationClientError
|
||||
userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
|
||||
[self didFinishWithResponse:response error:error];
|
||||
}];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)failExternalUserAgentFlowWithError:(NSError *)error {
|
||||
[self didFinishWithResponse:nil error:error];
|
||||
}
|
||||
|
||||
/*! @brief Invokes the pending callback and performs cleanup.
|
||||
@param response The authorization response, if any to return to the callback.
|
||||
@param error The error, if any, to return to the callback.
|
||||
*/
|
||||
- (void)didFinishWithResponse:(nullable OIDAuthorizationResponse *)response
|
||||
error:(nullable NSError *)error {
|
||||
OIDAuthorizationCallback callback = _pendingauthorizationFlowCallback;
|
||||
_pendingauthorizationFlowCallback = nil;
|
||||
_externalUserAgent = nil;
|
||||
if (callback) {
|
||||
callback(response, error);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface OIDEndSessionImplementation : NSObject<OIDExternalUserAgentSession> {
|
||||
// private variables
|
||||
OIDEndSessionRequest *_request;
|
||||
id<OIDExternalUserAgent> _externalUserAgent;
|
||||
OIDEndSessionCallback _pendingEndSessionCallback;
|
||||
}
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithRequest:(OIDEndSessionRequest *)request
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
|
||||
@implementation OIDEndSessionImplementation
|
||||
|
||||
- (instancetype)initWithRequest:(OIDEndSessionRequest *)request {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)presentAuthorizationWithExternalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDEndSessionCallback)authorizationFlowCallback {
|
||||
_externalUserAgent = externalUserAgent;
|
||||
_pendingEndSessionCallback = authorizationFlowCallback;
|
||||
BOOL authorizationFlowStarted =
|
||||
[_externalUserAgent presentExternalUserAgentRequest:_request session:self];
|
||||
if (!authorizationFlowStarted) {
|
||||
NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
|
||||
underlyingError:nil
|
||||
description:@"Unable to open Safari."];
|
||||
[self didFinishWithResponse:nil error:safariError];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
[self cancelWithCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)cancelWithCompletion:(nullable void (^)(void))completion {
|
||||
[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
|
||||
NSError *error = [OIDErrorUtilities
|
||||
errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
|
||||
underlyingError:nil
|
||||
description:nil];
|
||||
[self didFinishWithResponse:nil error:error];
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)shouldHandleURL:(NSURL *)URL {
|
||||
// The logic of when to handle the URL is the same as for authorization requests: should match
|
||||
// down to the path component.
|
||||
return [[OIDAuthorizationSession class] URL:URL
|
||||
matchesRedirectionURL:_request.postLogoutRedirectURL];
|
||||
}
|
||||
|
||||
- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL {
|
||||
// rejects URLs that don't match redirect (these may be completely unrelated to the authorization)
|
||||
if (![self shouldHandleURL:URL]) {
|
||||
return NO;
|
||||
}
|
||||
// checks for an invalid state
|
||||
if (!_pendingEndSessionCallback) {
|
||||
[NSException raise:OIDOAuthExceptionInvalidAuthorizationFlow
|
||||
format:@"%@", OIDOAuthExceptionInvalidAuthorizationFlow, nil];
|
||||
}
|
||||
|
||||
|
||||
NSError *error;
|
||||
OIDEndSessionResponse *response = nil;
|
||||
|
||||
OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] initWithURL:URL];
|
||||
response = [[OIDEndSessionResponse alloc] initWithRequest:_request
|
||||
parameters:query.dictionaryValue];
|
||||
|
||||
// verifies that the state in the response matches the state in the request, or both are nil
|
||||
if (!OIDIsEqualIncludingNil(_request.state, response.state)) {
|
||||
NSMutableDictionary *userInfo = [query.dictionaryValue mutableCopy];
|
||||
userInfo[NSLocalizedDescriptionKey] =
|
||||
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
|
||||
"response %@",
|
||||
_request.state,
|
||||
response.state,
|
||||
response];
|
||||
response = nil;
|
||||
error = [NSError errorWithDomain:OIDOAuthAuthorizationErrorDomain
|
||||
code:OIDErrorCodeOAuthAuthorizationClientError
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
|
||||
[self didFinishWithResponse:response error:error];
|
||||
}];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)failExternalUserAgentFlowWithError:(NSError *)error {
|
||||
[self didFinishWithResponse:nil error:error];
|
||||
}
|
||||
|
||||
/*! @brief Invokes the pending callback and performs cleanup.
|
||||
@param response The authorization response, if any to return to the callback.
|
||||
@param error The error, if any, to return to the callback.
|
||||
*/
|
||||
- (void)didFinishWithResponse:(nullable OIDEndSessionResponse *)response
|
||||
error:(nullable NSError *)error {
|
||||
OIDEndSessionCallback callback = _pendingEndSessionCallback;
|
||||
_pendingEndSessionCallback = nil;
|
||||
_externalUserAgent = nil;
|
||||
if (callback) {
|
||||
callback(response, error);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OIDAuthorizationService
|
||||
|
||||
+ (void)discoverServiceConfigurationForIssuer:(NSURL *)issuerURL
|
||||
completion:(OIDDiscoveryCallback)completion {
|
||||
NSURL *fullDiscoveryURL =
|
||||
[issuerURL URLByAppendingPathComponent:kOpenIDConfigurationWellKnownPath];
|
||||
|
||||
[[self class] discoverServiceConfigurationForDiscoveryURL:fullDiscoveryURL
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
+ (void)discoverServiceConfigurationForDiscoveryURL:(NSURL *)discoveryURL
|
||||
completion:(OIDDiscoveryCallback)completion {
|
||||
|
||||
NSURLSession *session = [OIDURLSessionProvider session];
|
||||
NSURLSessionDataTask *task =
|
||||
[session dataTaskWithURL:discoveryURL
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
// If we got any sort of error, just report it.
|
||||
if (error || !data) {
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Connection error fetching discovery document '%@': %@.",
|
||||
discoveryURL,
|
||||
error.localizedDescription];
|
||||
error = [OIDErrorUtilities errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:error
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response;
|
||||
|
||||
// Check for non-200 status codes.
|
||||
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
|
||||
if (urlResponse.statusCode != 200) {
|
||||
NSError *URLResponseError = [OIDErrorUtilities HTTPErrorWithHTTPResponse:urlResponse
|
||||
data:data];
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Non-200 HTTP response (%d) fetching discovery document "
|
||||
"'%@'.",
|
||||
(int)urlResponse.statusCode,
|
||||
discoveryURL];
|
||||
error = [OIDErrorUtilities errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:URLResponseError
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct an OIDServiceDiscovery with the received JSON.
|
||||
OIDServiceDiscovery *discovery =
|
||||
[[OIDServiceDiscovery alloc] initWithJSONData:data error:&error];
|
||||
if (error || !discovery) {
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"JSON error parsing document at '%@': %@",
|
||||
discoveryURL,
|
||||
error.localizedDescription];
|
||||
error = [OIDErrorUtilities errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:error
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Create our service configuration with the discovery document and return it.
|
||||
OIDServiceConfiguration *configuration =
|
||||
[[OIDServiceConfiguration alloc] initWithDiscoveryDocument:discovery];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(configuration, nil);
|
||||
});
|
||||
}];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
#pragma mark - Authorization Endpoint
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>) presentAuthorizationRequest:(OIDAuthorizationRequest *)request
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDAuthorizationCallback)callback {
|
||||
|
||||
AppAuthRequestTrace(@"Authorization Request: %@", request);
|
||||
|
||||
OIDAuthorizationSession *flowSession = [[OIDAuthorizationSession alloc] initWithRequest:request];
|
||||
[flowSession presentAuthorizationWithExternalUserAgent:externalUserAgent callback:callback];
|
||||
return flowSession;
|
||||
}
|
||||
|
||||
+ (id<OIDExternalUserAgentSession>)
|
||||
presentEndSessionRequest:(OIDEndSessionRequest *)request
|
||||
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
|
||||
callback:(OIDEndSessionCallback)callback {
|
||||
OIDEndSessionImplementation *flowSession =
|
||||
[[OIDEndSessionImplementation alloc] initWithRequest:request];
|
||||
[flowSession presentAuthorizationWithExternalUserAgent:externalUserAgent callback:callback];
|
||||
return flowSession;
|
||||
}
|
||||
|
||||
#pragma mark - Token Endpoint
|
||||
|
||||
+ (void)performTokenRequest:(OIDTokenRequest *)request callback:(OIDTokenCallback)callback {
|
||||
[[self class] performTokenRequest:request
|
||||
originalAuthorizationResponse:nil
|
||||
callback:callback];
|
||||
}
|
||||
|
||||
+ (void)performTokenRequest:(OIDTokenRequest *)request
|
||||
originalAuthorizationResponse:(OIDAuthorizationResponse *_Nullable)authorizationResponse
|
||||
callback:(OIDTokenCallback)callback {
|
||||
|
||||
NSURLRequest *URLRequest = [request URLRequest];
|
||||
|
||||
AppAuthRequestTrace(@"Token Request: %@\nHeaders:%@\nHTTPBody: %@",
|
||||
URLRequest.URL,
|
||||
URLRequest.allHTTPHeaderFields,
|
||||
[[NSString alloc] initWithData:URLRequest.HTTPBody
|
||||
encoding:NSUTF8StringEncoding]);
|
||||
|
||||
NSURLSession *session = [OIDURLSessionProvider session];
|
||||
[[session dataTaskWithRequest:URLRequest
|
||||
completionHandler:^(NSData *_Nullable data,
|
||||
NSURLResponse *_Nullable response,
|
||||
NSError *_Nullable error) {
|
||||
if (error) {
|
||||
// A network error or server error occurred.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Connection error making token request to '%@': %@.",
|
||||
URLRequest.URL,
|
||||
error.localizedDescription];
|
||||
NSError *returnedError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:error
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSHTTPURLResponse *HTTPURLResponse = (NSHTTPURLResponse *)response;
|
||||
NSInteger statusCode = HTTPURLResponse.statusCode;
|
||||
AppAuthRequestTrace(@"Token Response: HTTP Status %d\nHTTPBody: %@",
|
||||
(int)statusCode,
|
||||
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
||||
if (statusCode != 200) {
|
||||
// A server error occurred.
|
||||
NSError *serverError =
|
||||
[OIDErrorUtilities HTTPErrorWithHTTPResponse:HTTPURLResponse data:data];
|
||||
|
||||
// HTTP 4xx may indicate an RFC6749 Section 5.2 error response, attempts to parse as such.
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
NSError *jsonDeserializationError;
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *json =
|
||||
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonDeserializationError];
|
||||
|
||||
// If the HTTP 4xx response parses as JSON and has an 'error' key, it's an OAuth error.
|
||||
// These errors are special as they indicate a problem with the authorization grant.
|
||||
if (json[OIDOAuthErrorFieldError]) {
|
||||
NSError *oauthError =
|
||||
[OIDErrorUtilities OAuthErrorWithDomain:OIDOAuthTokenErrorDomain
|
||||
OAuthResponse:json
|
||||
underlyingError:serverError];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, oauthError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Status code indicates this is an error, but not an RFC6749 Section 5.2 error.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Non-200 HTTP response (%d) making token request to '%@'.",
|
||||
(int)statusCode,
|
||||
URLRequest.URL];
|
||||
NSError *returnedError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeServerError
|
||||
underlyingError:serverError
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *jsonDeserializationError;
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *json =
|
||||
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonDeserializationError];
|
||||
if (jsonDeserializationError) {
|
||||
// A problem occurred deserializing the response/JSON.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"JSON error parsing token response: %@",
|
||||
jsonDeserializationError.localizedDescription];
|
||||
NSError *returnedError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeJSONDeserializationError
|
||||
underlyingError:jsonDeserializationError
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
OIDTokenResponse *tokenResponse =
|
||||
[[OIDTokenResponse alloc] initWithRequest:request parameters:json];
|
||||
if (!tokenResponse) {
|
||||
// A problem occurred constructing the token response from the JSON.
|
||||
NSError *returnedError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeTokenResponseConstructionError
|
||||
underlyingError:jsonDeserializationError
|
||||
description:@"Token response invalid."];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// If an ID Token is included in the response, validates the ID Token following the rules
|
||||
// in OpenID Connect Core Section 3.1.3.7 for features that AppAuth directly supports
|
||||
// (which excludes rules #1, #4, #5, #7, #8, #12, and #13). Regarding rule #6, ID Tokens
|
||||
// received by this class are received via direct communication between the Client and the Token
|
||||
// Endpoint, thus we are exercising the option to rely only on the TLS validation. AppAuth
|
||||
// has a zero dependencies policy, and verifying the JWT signature would add a dependency.
|
||||
// Users of the library are welcome to perform the JWT signature verification themselves should
|
||||
// they wish.
|
||||
if (tokenResponse.idToken) {
|
||||
OIDIDToken *idToken = [[OIDIDToken alloc] initWithIDTokenString:tokenResponse.idToken];
|
||||
if (!idToken) {
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenParsingError
|
||||
underlyingError:nil
|
||||
description:@"ID Token parsing failed"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #1
|
||||
// Not supported: AppAuth does not support JWT encryption.
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #2
|
||||
// Validates that the issuer in the ID Token matches that of the discovery document.
|
||||
NSURL *issuer = tokenResponse.request.configuration.issuer;
|
||||
if (issuer && ![idToken.issuer isEqual:issuer]) {
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenFailedValidationError
|
||||
underlyingError:nil
|
||||
description:@"Issuer mismatch"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #3 & Section 2 azp Claim
|
||||
// Validates that the aud (audience) Claim contains the client ID, or that the azp
|
||||
// (authorized party) Claim matches the client ID.
|
||||
NSString *clientID = tokenResponse.request.clientID;
|
||||
if (![idToken.audience containsObject:clientID] &&
|
||||
![idToken.claims[@"azp"] isEqualToString:clientID]) {
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenFailedValidationError
|
||||
underlyingError:nil
|
||||
description:@"Audience mismatch"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rules #4 & #5
|
||||
// Not supported.
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #6
|
||||
// As noted above, AppAuth only supports the code flow which results in direct communication
|
||||
// of the ID Token from the Token Endpoint to the Client, and we are exercising the option to
|
||||
// use TSL server validation instead of checking the token signature. Users may additionally
|
||||
// check the token signature should they wish.
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rules #7 & #8
|
||||
// Not applicable. See rule #6.
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #9
|
||||
// Validates that the current time is before the expiry time.
|
||||
NSTimeInterval expiresAtDifference = [idToken.expiresAt timeIntervalSinceNow];
|
||||
if (expiresAtDifference < 0) {
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenFailedValidationError
|
||||
underlyingError:nil
|
||||
description:@"ID Token expired"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #10
|
||||
// Validates that the issued at time is not more than +/- 10 minutes on the current time.
|
||||
NSTimeInterval issuedAtDifference = [idToken.issuedAt timeIntervalSinceNow];
|
||||
if (fabs(issuedAtDifference) > kOIDAuthorizationSessionIATMaxSkew) {
|
||||
NSString *message =
|
||||
[NSString stringWithFormat:@"Issued at time is more than %d seconds before or after "
|
||||
"the current time",
|
||||
kOIDAuthorizationSessionIATMaxSkew];
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenFailedValidationError
|
||||
underlyingError:nil
|
||||
description:message];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Only relevant for the authorization_code response type
|
||||
if ([tokenResponse.request.grantType isEqual:OIDGrantTypeAuthorizationCode]) {
|
||||
// OpenID Connect Core Section 3.1.3.7. rule #11
|
||||
// Validates the nonce.
|
||||
NSString *nonce = authorizationResponse.request.nonce;
|
||||
if (nonce && ![idToken.nonce isEqual:nonce]) {
|
||||
NSError *invalidIDToken =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeIDTokenFailedValidationError
|
||||
underlyingError:nil
|
||||
description:@"Nonce mismatch"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(nil, invalidIDToken);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rules #12
|
||||
// ACR is not directly supported by AppAuth.
|
||||
|
||||
// OpenID Connect Core Section 3.1.3.7. rules #12
|
||||
// max_age is not directly supported by AppAuth.
|
||||
}
|
||||
|
||||
// Success
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(tokenResponse, nil);
|
||||
});
|
||||
}] resume];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Registration Endpoint
|
||||
|
||||
+ (void)performRegistrationRequest:(OIDRegistrationRequest *)request
|
||||
completion:(OIDRegistrationCompletion)completion {
|
||||
NSURLRequest *URLRequest = [request URLRequest];
|
||||
if (!URLRequest) {
|
||||
// A problem occurred deserializing the response/JSON.
|
||||
NSError *returnedError = [OIDErrorUtilities errorWithCode:OIDErrorCodeJSONSerializationError
|
||||
underlyingError:nil
|
||||
description:@"The registration request could not "
|
||||
"be serialized as JSON."];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSURLSession *session = [OIDURLSessionProvider session];
|
||||
[[session dataTaskWithRequest:URLRequest
|
||||
completionHandler:^(NSData *_Nullable data,
|
||||
NSURLResponse *_Nullable response,
|
||||
NSError *_Nullable error) {
|
||||
if (error) {
|
||||
// A network error or server error occurred.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Connection error making registration request to '%@': %@.",
|
||||
URLRequest.URL,
|
||||
error.localizedDescription];
|
||||
NSError *returnedError = [OIDErrorUtilities errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:error
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSHTTPURLResponse *HTTPURLResponse = (NSHTTPURLResponse *) response;
|
||||
|
||||
if (HTTPURLResponse.statusCode != 201 && HTTPURLResponse.statusCode != 200) {
|
||||
// A server error occurred.
|
||||
NSError *serverError = [OIDErrorUtilities HTTPErrorWithHTTPResponse:HTTPURLResponse
|
||||
data:data];
|
||||
|
||||
// HTTP 400 may indicate an OpenID Connect Dynamic Client Registration 1.0 Section 3.3 error
|
||||
// response, checks for that
|
||||
if (HTTPURLResponse.statusCode == 400) {
|
||||
NSError *jsonDeserializationError;
|
||||
NSDictionary<NSString *, NSObject <NSCopying> *> *json =
|
||||
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonDeserializationError];
|
||||
|
||||
// if the HTTP 400 response parses as JSON and has an 'error' key, it's an OAuth error
|
||||
// these errors are special as they indicate a problem with the authorization grant
|
||||
if (json[OIDOAuthErrorFieldError]) {
|
||||
NSError *oauthError =
|
||||
[OIDErrorUtilities OAuthErrorWithDomain:OIDOAuthRegistrationErrorDomain
|
||||
OAuthResponse:json
|
||||
underlyingError:serverError];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, oauthError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not an OAuth error, just a generic server error
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Non-200/201 HTTP response (%d) making registration request "
|
||||
"to '%@'.",
|
||||
(int)HTTPURLResponse.statusCode,
|
||||
URLRequest.URL];
|
||||
NSError *returnedError = [OIDErrorUtilities errorWithCode:OIDErrorCodeServerError
|
||||
underlyingError:serverError
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *jsonDeserializationError;
|
||||
NSDictionary<NSString *, NSObject <NSCopying> *> *json =
|
||||
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonDeserializationError];
|
||||
if (jsonDeserializationError) {
|
||||
// A problem occurred deserializing the response/JSON.
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"JSON error parsing registration response: %@",
|
||||
jsonDeserializationError.localizedDescription];
|
||||
NSError *returnedError = [OIDErrorUtilities errorWithCode:OIDErrorCodeJSONDeserializationError
|
||||
underlyingError:jsonDeserializationError
|
||||
description:errorDescription];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
OIDRegistrationResponse *registrationResponse =
|
||||
[[OIDRegistrationResponse alloc] initWithRequest:request
|
||||
parameters:json];
|
||||
if (!registrationResponse) {
|
||||
// A problem occurred constructing the registration response from the JSON.
|
||||
NSError *returnedError =
|
||||
[OIDErrorUtilities errorWithCode:OIDErrorCodeRegistrationResponseConstructionError
|
||||
underlyingError:nil
|
||||
description:@"Registration response invalid."];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(nil, returnedError);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Success
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(registrationResponse, nil);
|
||||
});
|
||||
}] resume];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
51
Pods/AppAuth/Source/AppAuthCore/OIDClientMetadataParameters.h
generated
Normal file
51
Pods/AppAuth/Source/AppAuthCore/OIDClientMetadataParameters.h
generated
Normal file
@ -0,0 +1,51 @@
|
||||
/*! @file OIDClientMetadataParameters.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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 Parameter name for the token endpoint authentication method.
|
||||
*/
|
||||
extern NSString *const OIDTokenEndpointAuthenticationMethodParam;
|
||||
|
||||
/*! @brief Parameter name for the application type.
|
||||
*/
|
||||
extern NSString *const OIDApplicationTypeParam;
|
||||
|
||||
/*! @brief Parameter name for the redirect URI values.
|
||||
*/
|
||||
extern NSString *const OIDRedirectURIsParam;
|
||||
|
||||
/*! @brief Parameter name for the response type values.
|
||||
*/
|
||||
extern NSString *const OIDResponseTypesParam;
|
||||
|
||||
/*! @brief Parameter name for the grant type values.
|
||||
*/
|
||||
extern NSString *const OIDGrantTypesParam;
|
||||
|
||||
/*! @brief Parameter name for the subject type.
|
||||
*/
|
||||
extern NSString *const OIDSubjectTypeParam;
|
||||
|
||||
/*! @brief Application type that indicates this client is a native (not a web) application.
|
||||
*/
|
||||
extern NSString *const OIDApplicationTypeNative;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
33
Pods/AppAuth/Source/AppAuthCore/OIDClientMetadataParameters.m
generated
Normal file
33
Pods/AppAuth/Source/AppAuthCore/OIDClientMetadataParameters.m
generated
Normal file
@ -0,0 +1,33 @@
|
||||
/*! @file OIDClientMetadataParameters.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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 "OIDClientMetadataParameters.h"
|
||||
|
||||
NSString *const OIDTokenEndpointAuthenticationMethodParam = @"token_endpoint_auth_method";
|
||||
|
||||
NSString *const OIDApplicationTypeParam = @"application_type";
|
||||
|
||||
NSString *const OIDRedirectURIsParam = @"redirect_uris";
|
||||
|
||||
NSString *const OIDResponseTypesParam = @"response_types";
|
||||
|
||||
NSString *const OIDGrantTypesParam = @"grant_types";
|
||||
|
||||
NSString *const OIDSubjectTypeParam = @"subject_type";
|
||||
|
||||
NSString *const OIDApplicationTypeNative = @"native";
|
||||
51
Pods/AppAuth/Source/AppAuthCore/OIDDefines.h
generated
Normal file
51
Pods/AppAuth/Source/AppAuthCore/OIDDefines.h
generated
Normal file
@ -0,0 +1,51 @@
|
||||
/*! @file OIDDefines.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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.
|
||||
*/
|
||||
|
||||
/*! @def OIDIsEqualIncludingNil(x, y)
|
||||
@brief Returns YES if x and y are equal by reference or value.
|
||||
@discussion NOTE: parameters may be evaluated multiple times. Be careful if using this check
|
||||
with expressions - especially if the expressions have side effects.
|
||||
@param x An object.
|
||||
@param y An object.
|
||||
*/
|
||||
#define OIDIsEqualIncludingNil(x, y) (((x) == (y)) || [(x) isEqual:(y)])
|
||||
|
||||
/*! @def OID_UNAVAILABLE_USE_INITIALIZER(designatedInitializer)
|
||||
@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 intializer's signature changes.
|
||||
@param designatedInitializer A SEL referencing the designated initializer.
|
||||
*/
|
||||
#define OID_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]; \
|
||||
}
|
||||
|
||||
#ifdef _APPAUTHTRACE
|
||||
# define AppAuthRequestTrace(fmt, ...) NSLog(fmt, ##__VA_ARGS__);
|
||||
#else // _APPAUTHTRACE
|
||||
# define AppAuthRequestTrace(...)
|
||||
#endif // _APPAUTHTRACE
|
||||
|
||||
107
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionRequest.h
generated
Normal file
107
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionRequest.h
generated
Normal file
@ -0,0 +1,107 @@
|
||||
/*! @file OIDEndSessionRequest.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
#import "OIDExternalUserAgentRequest.h"
|
||||
|
||||
@class OIDServiceConfiguration;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OIDEndSessionRequest : NSObject
|
||||
<NSCopying, NSSecureCoding, OIDExternalUserAgentRequest>
|
||||
|
||||
/*! @brief The service's configuration.
|
||||
@remarks This configuration specifies how to connect to a particular OAuth provider.
|
||||
Configurations may be created manually, or via an OpenID Connect Discovery Document.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDServiceConfiguration *configuration;
|
||||
|
||||
/*! @brief The client's redirect URI.
|
||||
@remarks post_logout_redirect_uri
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *postLogoutRedirectURL;
|
||||
|
||||
/*! @brief Previously issued ID Token passed to the end session endpoint as a hint about the End-User's current authenticated
|
||||
session with the Client
|
||||
@remarks id_token_hint
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *idTokenHint;
|
||||
|
||||
/*! @brief An opaque value used by the client to maintain state between the request and callback.
|
||||
@remarks state
|
||||
@discussion If this value is not explicitly set, this library will automatically add state and
|
||||
perform appropriate validation of the state in the authorization response. It is recommended
|
||||
that the default implementation of this parameter be used wherever possible. Typically used
|
||||
to prevent CSRF attacks, as recommended in RFC6819 Section 5.3.5.
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *state;
|
||||
|
||||
/*! @brief The client's additional authorization parameters.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithConfiguration:clientId:scopes:redirectURL:additionalParameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Creates an authorization request with opinionated defaults (a secure @c state).
|
||||
@param configuration The service's configuration.
|
||||
@param idTokenHint The previously issued ID Token
|
||||
@param postLogoutRedirectURL The client's post-logout redirect URI.
|
||||
callback.
|
||||
@param additionalParameters The client's additional authorization parameters.
|
||||
*/
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
idTokenHint:(NSString *)idTokenHint
|
||||
postLogoutRedirectURL:(NSURL *)postLogoutRedirectURL
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param configuration The service's configuration.
|
||||
@param idTokenHint The previously issued ID Token
|
||||
@param postLogoutRedirectURL The client's post-logout redirect URI.
|
||||
@param state An opaque value used by the client to maintain state between the request and
|
||||
callback.
|
||||
@param additionalParameters The client's additional authorization parameters.
|
||||
*/
|
||||
- (instancetype)
|
||||
initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
idTokenHint:(NSString *)idTokenHint
|
||||
postLogoutRedirectURL:(NSURL *)postLogoutRedirectURL
|
||||
state:(NSString *)state
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Constructs the request URI by adding the request parameters to the query component of the
|
||||
authorization endpoint URI using the "application/x-www-form-urlencoded" format.
|
||||
@return A URL representing the authorization request.
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
- (NSURL *)endSessionRequestURL;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
190
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionRequest.m
generated
Normal file
190
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionRequest.m
generated
Normal file
@ -0,0 +1,190 @@
|
||||
/*! @file OIDEndSessionRequest.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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 "OIDEndSessionRequest.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDServiceDiscovery.h"
|
||||
#import "OIDURLQueryComponent.h"
|
||||
|
||||
/*! @brief The key for the @c configuration property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kConfigurationKey = @"configuration";
|
||||
|
||||
/*! @brief Key used to encode the @c state property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kStateKey = @"state";
|
||||
|
||||
/*! @brief Key used to encode the @c postLogoutRedirectURL property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kPostLogoutRedirectURLKey = @"post_logout_redirect_uri";
|
||||
|
||||
/*! @brief Key used to encode the @c idTokenHint property for @c NSSecureCoding, and on the URL request.
|
||||
*/
|
||||
static NSString *const kIdTokenHintKey = @"id_token_hint";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
/*! @brief Number of random bytes generated for the @state.
|
||||
*/
|
||||
static NSUInteger const kStateSizeBytes = 32;
|
||||
|
||||
/*! @brief Assertion text for missing end_session_endpoint.
|
||||
*/
|
||||
static NSString *const OIDMissingEndSessionEndpointMessage =
|
||||
@"The service configuration is missing an end_session_endpoint.";
|
||||
|
||||
@implementation OIDEndSessionRequest
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(
|
||||
@selector(initWithConfiguration:
|
||||
idTokenHint:
|
||||
postLogoutRedirectURL:
|
||||
additionalParameters:)
|
||||
)
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
idTokenHint:(NSString *)idTokenHint
|
||||
postLogoutRedirectURL:(NSURL *)postLogoutRedirectURL
|
||||
state:(NSString *)state
|
||||
additionalParameters:(NSDictionary<NSString *,NSString *> *)additionalParameters
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configuration = [configuration copy];
|
||||
_idTokenHint = [idTokenHint copy];
|
||||
_postLogoutRedirectURL = [postLogoutRedirectURL copy];
|
||||
_state = [state copy];
|
||||
_additionalParameters =
|
||||
[[NSDictionary alloc] initWithDictionary:additionalParameters copyItems:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
idTokenHint:(NSString *)idTokenHint
|
||||
postLogoutRedirectURL:(NSURL *)postLogoutRedirectURL
|
||||
additionalParameters:(NSDictionary<NSString *,NSString *> *)additionalParameters
|
||||
{
|
||||
return [self initWithConfiguration:configuration
|
||||
idTokenHint:idTokenHint
|
||||
postLogoutRedirectURL:postLogoutRedirectURL
|
||||
state:[[self class] generateState]
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDServiceConfiguration *configuration = [aDecoder decodeObjectOfClass:[OIDServiceConfiguration class] forKey:kConfigurationKey];
|
||||
|
||||
NSString *idTokenHint = [aDecoder decodeObjectOfClass:[NSString class] forKey:kIdTokenHintKey];
|
||||
NSURL *postLogoutRedirectURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPostLogoutRedirectURLKey];
|
||||
NSString *state = [aDecoder decodeObjectOfClass:[NSString class] forKey:kStateKey];
|
||||
NSSet *additionalParameterCodingClasses = [NSSet setWithArray:@[
|
||||
[NSDictionary class],
|
||||
[NSString class]
|
||||
]];
|
||||
NSDictionary *additionalParameters = [aDecoder decodeObjectOfClasses:additionalParameterCodingClasses
|
||||
forKey:kAdditionalParametersKey];
|
||||
|
||||
self = [self initWithConfiguration:configuration
|
||||
idTokenHint:idTokenHint
|
||||
postLogoutRedirectURL:postLogoutRedirectURL
|
||||
state:state
|
||||
additionalParameters:additionalParameters];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_configuration forKey:kConfigurationKey];
|
||||
[aCoder encodeObject:_idTokenHint forKey:kIdTokenHintKey];
|
||||
[aCoder encodeObject:_postLogoutRedirectURL forKey:kPostLogoutRedirectURLKey];
|
||||
[aCoder encodeObject:_state forKey:kStateKey];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
self.endSessionRequestURL];
|
||||
}
|
||||
|
||||
+ (nullable NSString *)generateState {
|
||||
return [OIDTokenUtilities randomURLSafeStringWithSize:kStateSizeBytes];
|
||||
}
|
||||
|
||||
#pragma mark - OIDExternalUserAgentRequest
|
||||
|
||||
- (NSURL*)externalUserAgentRequestURL {
|
||||
return [self endSessionRequestURL];
|
||||
}
|
||||
|
||||
- (NSString *)redirectScheme {
|
||||
return [_postLogoutRedirectURL scheme];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSURL *)endSessionRequestURL {
|
||||
OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] init];
|
||||
|
||||
// Add any additional parameters the client has specified.
|
||||
[query addParameters:_additionalParameters];
|
||||
|
||||
// Add optional parameters, as applicable.
|
||||
if (_idTokenHint) {
|
||||
[query addParameter:kIdTokenHintKey value:_idTokenHint];
|
||||
}
|
||||
|
||||
if (_postLogoutRedirectURL) {
|
||||
[query addParameter:kPostLogoutRedirectURLKey value:_postLogoutRedirectURL.absoluteString];
|
||||
}
|
||||
|
||||
if (_state) {
|
||||
[query addParameter:kStateKey value:_state];
|
||||
}
|
||||
|
||||
NSAssert(_configuration.endSessionEndpoint, OIDMissingEndSessionEndpointMessage);
|
||||
|
||||
// Construct the URL
|
||||
return [query URLByReplacingQueryInURL:_configuration.endSessionEndpoint];
|
||||
}
|
||||
|
||||
@end
|
||||
64
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionResponse.h
generated
Normal file
64
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionResponse.h
generated
Normal file
@ -0,0 +1,64 @@
|
||||
/*! @file OIDEndSessionResponse.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDEndSessionRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents the response to an End Session request.
|
||||
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
|
||||
*/
|
||||
|
||||
@interface OIDEndSessionResponse : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The request which was serviced.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDEndSessionRequest *request;
|
||||
|
||||
/*! @brief REQUIRED if the "state" parameter was present in the client end-session request. The
|
||||
exact value received from the client.
|
||||
@remarks state
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *state;
|
||||
|
||||
/*! @brief Additional parameters returned from the end session endpoint.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithParameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param request The serviced request.
|
||||
@param parameters The decoded parameters returned from the End Session Endpoint.
|
||||
@remarks Known parameters are extracted from the @c parameters parameter and the normative
|
||||
properties are populated. Non-normative parameters are placed in the
|
||||
@c #additionalParameters dictionary.
|
||||
*/
|
||||
- (instancetype)initWithRequest:(OIDEndSessionRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
118
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionResponse.m
generated
Normal file
118
Pods/AppAuth/Source/AppAuthCore/OIDEndSessionResponse.m
generated
Normal file
@ -0,0 +1,118 @@
|
||||
/*! @file OIDEndSessionResponse.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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 "OIDEndSessionResponse.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDEndSessionRequest.h"
|
||||
#import "OIDFieldMapping.h"
|
||||
|
||||
/*! @brief The key for the @c state property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kStateKey = @"state";
|
||||
|
||||
/*! @brief Key used to encode the @c request property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRequestKey = @"request";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for
|
||||
@c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
@implementation OIDEndSessionResponse
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithRequest:parameters:))
|
||||
|
||||
- (instancetype)initWithRequest:(OIDEndSessionRequest *)request
|
||||
parameters:(NSDictionary<NSString *,NSObject<NSCopying> *> *)parameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters =
|
||||
[OIDFieldMapping remainingParametersWithMap:[[self class] fieldMap]
|
||||
parameters:parameters
|
||||
instance:self];
|
||||
_additionalParameters = additionalParameters;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*! @brief Returns a mapping of incoming parameters to instance variables.
|
||||
@return A mapping of incoming parameters to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, OIDFieldMapping *> *)fieldMap {
|
||||
static NSMutableDictionary<NSString *, OIDFieldMapping *> *fieldMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
fieldMap = [NSMutableDictionary dictionary];
|
||||
fieldMap[kStateKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_state" type:[NSString class]];
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDEndSessionRequest *request =
|
||||
[aDecoder decodeObjectOfClass:[OIDEndSessionRequest class] forKey:kRequestKey];
|
||||
self = [self initWithRequest:request parameters:@{ }];
|
||||
if (self) {
|
||||
[OIDFieldMapping decodeWithCoder:aDecoder map:[[self class] fieldMap] instance:self];
|
||||
_additionalParameters = [aDecoder decodeObjectOfClasses:[OIDFieldMapping JSONTypes]
|
||||
forKey:kAdditionalParametersKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_request forKey:kRequestKey];
|
||||
[OIDFieldMapping encodeWithCoder:aCoder map:[[self class] fieldMap] instance:self];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, state: \"%@\", "
|
||||
"additionalParameters: %@, request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
_state,
|
||||
_additionalParameters,
|
||||
_request];
|
||||
}
|
||||
@end
|
||||
393
Pods/AppAuth/Source/AppAuthCore/OIDError.h
generated
Normal file
393
Pods/AppAuth/Source/AppAuthCore/OIDError.h
generated
Normal file
@ -0,0 +1,393 @@
|
||||
/*! @file OIDError.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 The error domain for all NSErrors returned from the AppAuth library.
|
||||
*/
|
||||
extern NSString *const OIDGeneralErrorDomain;
|
||||
|
||||
/*! @brief The error domain for OAuth specific errors on the authorization endpoint.
|
||||
@discussion This error domain is used when the server responds to an authorization request
|
||||
with an explicit OAuth error, as defined by RFC6749 Section 4.1.2.1. If the authorization
|
||||
response is invalid and not explicitly an error response, another error domain will be used.
|
||||
The error response parameter dictionary is available in the
|
||||
\NSError_userInfo dictionary using the @c ::OIDOAuthErrorResponseErrorKey key.
|
||||
The \NSError_code will be one of the @c ::OIDErrorCodeOAuthAuthorization enum values.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
extern NSString *const OIDOAuthAuthorizationErrorDomain;
|
||||
|
||||
/*! @brief The error domain for OAuth specific errors on the token endpoint.
|
||||
@discussion This error domain is used when the server responds with HTTP 400 and an OAuth error,
|
||||
as defined RFC6749 Section 5.2. If an HTTP 400 response does not parse as an OAuth error
|
||||
(i.e. no 'error' field is present or the JSON is invalid), another error domain will be
|
||||
used. The entire OAuth error response dictionary is available in the \NSError_userInfo
|
||||
dictionary using the @c ::OIDOAuthErrorResponseErrorKey key. Unlike transient network
|
||||
errors, errors in this domain invalidate the authentication state, and either indicate a
|
||||
client error or require user interaction (i.e. reauthentication) to resolve.
|
||||
The \NSError_code will be one of the @c ::OIDErrorCodeOAuthToken enum values.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
extern NSString *const OIDOAuthTokenErrorDomain;
|
||||
|
||||
/*! @brief The error domain for dynamic client registration errors.
|
||||
@discussion This error domain is used when the server responds with HTTP 400 and an OAuth error,
|
||||
as defined in OpenID Connect Dynamic Client Registration 1.0 Section 3.3. If an HTTP 400
|
||||
response does not parse as an OAuth error (i.e. no 'error' field is present or the JSON is
|
||||
invalid), another error domain will be used. The entire OAuth error response dictionary is
|
||||
available in the \NSError_userInfo dictionary using the @c ::OIDOAuthErrorResponseErrorKey
|
||||
key. Unlike transient network errors, errors in this domain invalidate the authentication
|
||||
state, and indicates a client error.
|
||||
The \NSError_code will be one of the @c ::OIDErrorCodeOAuthToken enum values.
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
extern NSString *const OIDOAuthRegistrationErrorDomain;
|
||||
|
||||
/*! @brief The error domain for authorization errors encountered out of band on the resource server.
|
||||
*/
|
||||
extern NSString *const OIDResourceServerAuthorizationErrorDomain;
|
||||
|
||||
/*! @brief An error domain representing received HTTP errors.
|
||||
*/
|
||||
extern NSString *const OIDHTTPErrorDomain;
|
||||
|
||||
/*! @brief An error key for the original OAuth error response (if any).
|
||||
*/
|
||||
extern NSString *const OIDOAuthErrorResponseErrorKey;
|
||||
|
||||
/*! @brief The key of the 'error' response field in a RFC6749 Section 5.2 response.
|
||||
@remark error
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
extern NSString *const OIDOAuthErrorFieldError;
|
||||
|
||||
/*! @brief The key of the 'error_description' response field in a RFC6749 Section 5.2 response.
|
||||
@remark error_description
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
extern NSString *const OIDOAuthErrorFieldErrorDescription;
|
||||
|
||||
/*! @brief The key of the 'error_uri' response field in a RFC6749 Section 5.2 response.
|
||||
@remark error_uri
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
extern NSString *const OIDOAuthErrorFieldErrorURI;
|
||||
|
||||
/*! @brief The various error codes returned from the AppAuth library.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, OIDErrorCode) {
|
||||
/*! @brief Indicates a problem parsing an OpenID Connect Service Discovery document.
|
||||
*/
|
||||
OIDErrorCodeInvalidDiscoveryDocument = -2,
|
||||
|
||||
/*! @brief Indicates the user manually canceled the OAuth authorization code flow.
|
||||
*/
|
||||
OIDErrorCodeUserCanceledAuthorizationFlow = -3,
|
||||
|
||||
/*! @brief Indicates an OAuth authorization flow was programmatically cancelled.
|
||||
*/
|
||||
OIDErrorCodeProgramCanceledAuthorizationFlow = -4,
|
||||
|
||||
/*! @brief Indicates a network error or server error occurred.
|
||||
*/
|
||||
OIDErrorCodeNetworkError = -5,
|
||||
|
||||
/*! @brief Indicates a server error occurred.
|
||||
*/
|
||||
OIDErrorCodeServerError = -6,
|
||||
|
||||
/*! @brief Indicates a problem occurred deserializing the response/JSON.
|
||||
*/
|
||||
OIDErrorCodeJSONDeserializationError = -7,
|
||||
|
||||
/*! @brief Indicates a problem occurred constructing the token response from the JSON.
|
||||
*/
|
||||
OIDErrorCodeTokenResponseConstructionError = -8,
|
||||
|
||||
/*! @brief @c UIApplication.openURL: returned NO when attempting to open the authorization
|
||||
request in mobile Safari.
|
||||
*/
|
||||
OIDErrorCodeSafariOpenError = -9,
|
||||
|
||||
/*! @brief @c NSWorkspace.openURL returned NO when attempting to open the authorization
|
||||
request in the default browser.
|
||||
*/
|
||||
OIDErrorCodeBrowserOpenError = -10,
|
||||
|
||||
/*! @brief Indicates a problem when trying to refresh the tokens.
|
||||
*/
|
||||
OIDErrorCodeTokenRefreshError = -11,
|
||||
|
||||
/*! @brief Indicates a problem occurred constructing the registration response from the JSON.
|
||||
*/
|
||||
OIDErrorCodeRegistrationResponseConstructionError = -12,
|
||||
|
||||
/*! @brief Indicates a problem occurred deserializing the response/JSON.
|
||||
*/
|
||||
OIDErrorCodeJSONSerializationError = -13,
|
||||
|
||||
/*! @brief The ID Token did not parse.
|
||||
*/
|
||||
OIDErrorCodeIDTokenParsingError = -14,
|
||||
|
||||
/*! @brief The ID Token did not pass validation (e.g. issuer, audience checks).
|
||||
*/
|
||||
OIDErrorCodeIDTokenFailedValidationError = -15,
|
||||
};
|
||||
|
||||
/*! @brief Enum of all possible OAuth error codes as defined by RFC6749
|
||||
@discussion Used by @c ::OIDErrorCodeOAuthAuthorization and @c ::OIDErrorCodeOAuthToken
|
||||
which define endpoint-specific subsets of OAuth codes. Those enum types are down-castable
|
||||
to this one.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-11.4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, OIDErrorCodeOAuth) {
|
||||
|
||||
/*! @remarks invalid_request
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidRequest = -2,
|
||||
|
||||
/*! @remarks unauthorized_client
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthUnauthorizedClient = -3,
|
||||
|
||||
/*! @remarks access_denied
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAccessDenied = -4,
|
||||
|
||||
/*! @remarks unsupported_response_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthUnsupportedResponseType = -5,
|
||||
|
||||
/*! @remarks invalid_scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidScope = -6,
|
||||
|
||||
/*! @remarks server_error
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthServerError = -7,
|
||||
|
||||
/*! @remarks temporarily_unavailable
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthTemporarilyUnavailable = -8,
|
||||
|
||||
/*! @remarks invalid_client
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidClient = -9,
|
||||
|
||||
/*! @remarks invalid_grant
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidGrant = -10,
|
||||
|
||||
/*! @remarks unsupported_grant_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthUnsupportedGrantType = -11,
|
||||
|
||||
/*! @remarks invalid_redirect_uri
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidRedirectURI = -12,
|
||||
|
||||
/*! @remarks invalid_client_metadata
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
OIDErrorCodeOAuthInvalidClientMetadata = -13,
|
||||
|
||||
/*! @brief An authorization error occurring on the client rather than the server. For example,
|
||||
due to a state mismatch or misconfiguration. Should be treated as an unrecoverable
|
||||
authorization error.
|
||||
*/
|
||||
OIDErrorCodeOAuthClientError = -0xEFFF,
|
||||
|
||||
/*! @brief An OAuth error not known to this library
|
||||
@discussion Indicates an OAuth error as per RFC6749, but the error code was not in our
|
||||
list. It could be a custom error code, or one from an OAuth extension. See the "error" key
|
||||
of the \NSError_userInfo property. Such errors are assumed to invalidate the
|
||||
authentication state
|
||||
*/
|
||||
OIDErrorCodeOAuthOther = -0xF000,
|
||||
};
|
||||
|
||||
/*! @brief The error codes for the @c ::OIDOAuthAuthorizationErrorDomain error domain
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, OIDErrorCodeOAuthAuthorization) {
|
||||
/*! @remarks invalid_request
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationInvalidRequest = OIDErrorCodeOAuthInvalidRequest,
|
||||
|
||||
/*! @remarks unauthorized_client
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationUnauthorizedClient = OIDErrorCodeOAuthUnauthorizedClient,
|
||||
|
||||
/*! @remarks access_denied
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationAccessDenied =
|
||||
OIDErrorCodeOAuthAccessDenied,
|
||||
|
||||
/*! @remarks unsupported_response_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationUnsupportedResponseType =
|
||||
OIDErrorCodeOAuthUnsupportedResponseType,
|
||||
|
||||
/*! @brief Indicates a network error or server error occurred.
|
||||
@remarks invalid_scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationAuthorizationInvalidScope = OIDErrorCodeOAuthInvalidScope,
|
||||
|
||||
/*! @brief Indicates a server error occurred.
|
||||
@remarks server_error
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationServerError = OIDErrorCodeOAuthServerError,
|
||||
|
||||
/*! @remarks temporarily_unavailable
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationTemporarilyUnavailable = OIDErrorCodeOAuthTemporarilyUnavailable,
|
||||
|
||||
/*! @brief An authorization error occurring on the client rather than the server. For example,
|
||||
due to a state mismatch or client misconfiguration. Should be treated as an unrecoverable
|
||||
authorization error.
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationClientError = OIDErrorCodeOAuthClientError,
|
||||
|
||||
/*! @brief An authorization OAuth error not known to this library
|
||||
@discussion this indicates an OAuth error as per RFC6749, but the error code was not in our
|
||||
list. It could be a custom error code, or one from an OAuth extension. See the "error" key
|
||||
of the \NSError_userInfo property. We assume such errors are not transient.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
*/
|
||||
OIDErrorCodeOAuthAuthorizationOther = OIDErrorCodeOAuthOther,
|
||||
};
|
||||
|
||||
|
||||
/*! @brief The error codes for the @c ::OIDOAuthTokenErrorDomain error domain
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, OIDErrorCodeOAuthToken) {
|
||||
/*! @remarks invalid_request
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenInvalidRequest = OIDErrorCodeOAuthInvalidRequest,
|
||||
|
||||
/*! @remarks invalid_client
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenInvalidClient = OIDErrorCodeOAuthInvalidClient,
|
||||
|
||||
/*! @remarks invalid_grant
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenInvalidGrant = OIDErrorCodeOAuthInvalidGrant,
|
||||
|
||||
/*! @remarks unauthorized_client
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenUnauthorizedClient = OIDErrorCodeOAuthUnauthorizedClient,
|
||||
|
||||
/*! @remarks unsupported_grant_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenUnsupportedGrantType = OIDErrorCodeOAuthUnsupportedGrantType,
|
||||
|
||||
/*! @remarks invalid_scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenInvalidScope = OIDErrorCodeOAuthInvalidScope,
|
||||
|
||||
/*! @brief An unrecoverable token error occurring on the client rather than the server.
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenClientError = OIDErrorCodeOAuthClientError,
|
||||
|
||||
/*! @brief A token endpoint OAuth error not known to this library
|
||||
@discussion this indicates an OAuth error as per RFC6749, but the error code was not in our
|
||||
list. It could be a custom error code, or one from an OAuth extension. See the "error" key
|
||||
of the \NSError_userInfo property. We assume such errors are not transient.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthTokenOther = OIDErrorCodeOAuthOther,
|
||||
};
|
||||
|
||||
/*! @brief The error codes for the @c ::OIDOAuthRegistrationErrorDomain error domain
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, OIDErrorCodeOAuthRegistration) {
|
||||
/*! @remarks invalid_request
|
||||
@see http://tools.ietf.org/html/rfc6750#section-3.1
|
||||
*/
|
||||
OIDErrorCodeOAuthRegistrationInvalidRequest = OIDErrorCodeOAuthInvalidRequest,
|
||||
|
||||
/*! @remarks invalid_redirect_uri
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
OIDErrorCodeOAuthRegistrationInvalidRedirectURI = OIDErrorCodeOAuthInvalidRedirectURI,
|
||||
|
||||
/*! @remarks invalid_client_metadata
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationError
|
||||
*/
|
||||
OIDErrorCodeOAuthRegistrationInvalidClientMetadata = OIDErrorCodeOAuthInvalidClientMetadata,
|
||||
|
||||
/*! @brief An unrecoverable token error occurring on the client rather than the server.
|
||||
*/
|
||||
OIDErrorCodeOAuthRegistrationClientError = OIDErrorCodeOAuthClientError,
|
||||
|
||||
/*! @brief A registration endpoint OAuth error not known to this library
|
||||
@discussion this indicates an OAuth error, but the error code was not in our
|
||||
list. It could be a custom error code, or one from an OAuth extension. See the "error" key
|
||||
of the \NSError_userInfo property. We assume such errors are not transient.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
OIDErrorCodeOAuthRegistrationOther = OIDErrorCodeOAuthOther,
|
||||
};
|
||||
|
||||
|
||||
/*! @brief The exception text for the exception which occurs when a
|
||||
@c OIDExternalUserAgentSession receives a message after it has already completed.
|
||||
*/
|
||||
extern NSString *const OIDOAuthExceptionInvalidAuthorizationFlow;
|
||||
|
||||
/*! @brief The text for the exception which occurs when a Token Request is constructed
|
||||
with a null redirectURL for a grant_type that requires a nonnull Redirect
|
||||
*/
|
||||
extern NSString *const OIDOAuthExceptionInvalidTokenRequestNullRedirectURL;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
45
Pods/AppAuth/Source/AppAuthCore/OIDError.m
generated
Normal file
45
Pods/AppAuth/Source/AppAuthCore/OIDError.m
generated
Normal file
@ -0,0 +1,45 @@
|
||||
/*! @file OIDError.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDError.h"
|
||||
|
||||
NSString *const OIDGeneralErrorDomain = @"org.openid.appauth.general";
|
||||
|
||||
NSString *const OIDOAuthTokenErrorDomain = @"org.openid.appauth.oauth_token";
|
||||
|
||||
NSString *const OIDOAuthAuthorizationErrorDomain = @"org.openid.appauth.oauth_authorization";
|
||||
|
||||
NSString *const OIDOAuthRegistrationErrorDomain = @"org.openid.appauth.oauth_registration";
|
||||
|
||||
NSString *const OIDResourceServerAuthorizationErrorDomain = @"org.openid.appauth.resourceserver";
|
||||
|
||||
NSString *const OIDHTTPErrorDomain = @"org.openid.appauth.remote-http";
|
||||
|
||||
NSString *const OIDOAuthExceptionInvalidAuthorizationFlow = @"An OAuth redirect was sent to a "
|
||||
"OIDExternalUserAgentSession after it already completed.";
|
||||
|
||||
NSString *const OIDOAuthExceptionInvalidTokenRequestNullRedirectURL = @"A OIDTokenRequest was "
|
||||
"created with a grant_type that requires a redirectURL, but a null redirectURL was given";
|
||||
|
||||
NSString *const OIDOAuthErrorResponseErrorKey = @"OIDOAuthErrorResponseErrorKey";
|
||||
|
||||
NSString *const OIDOAuthErrorFieldError = @"error";
|
||||
|
||||
NSString *const OIDOAuthErrorFieldErrorDescription = @"error_description";
|
||||
|
||||
NSString *const OIDOAuthErrorFieldErrorURI = @"error_uri";
|
||||
107
Pods/AppAuth/Source/AppAuthCore/OIDErrorUtilities.h
generated
Normal file
107
Pods/AppAuth/Source/AppAuthCore/OIDErrorUtilities.h
generated
Normal file
@ -0,0 +1,107 @@
|
||||
/*! @file OIDErrorUtilities.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
#import "OIDError.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Convenience methods for creating standardized \NSError instances.
|
||||
*/
|
||||
@interface OIDErrorUtilities : NSObject
|
||||
|
||||
/*! @brief Creates a standard \NSError from an @c ::OIDErrorCode and custom user info.
|
||||
Automatically populates the localized error description.
|
||||
@param code The error code.
|
||||
@param underlyingError The underlying error which occurred, if applicable.
|
||||
@param description A custom description, if applicable.
|
||||
@return An \NSError representing the error code.
|
||||
*/
|
||||
+ (NSError *)errorWithCode:(OIDErrorCode)code
|
||||
underlyingError:(nullable NSError *)underlyingError
|
||||
description:(nullable NSString *)description;
|
||||
|
||||
/*! @brief Creates a standard \NSError from an @c ::OIDErrorCode and custom user info.
|
||||
Automatically populates the localized error description.
|
||||
@param OAuthErrorDomain The OAuth error domain. Must be @c ::OIDOAuthAuthorizationErrorDomain or
|
||||
@c ::OIDOAuthTokenErrorDomain.
|
||||
@param errorResponse The dictionary from an OAuth error response (as per RFC6749 Section 5.2).
|
||||
@param underlyingError The underlying error which occurred, if applicable.
|
||||
@return An \NSError representing the OAuth error.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
+ (NSError *)OAuthErrorWithDomain:(NSString *)OAuthErrorDomain
|
||||
OAuthResponse:(NSDictionary *)errorResponse
|
||||
underlyingError:(nullable NSError *)underlyingError;
|
||||
|
||||
/*! @brief Creates a \NSError indicating that the resource server responded with an authorization
|
||||
error.
|
||||
@param code Your error code.
|
||||
@param errorResponse The resource server error response, if any.
|
||||
@param underlyingError The underlying error which occurred, if applicable.
|
||||
@return An \NSError representing the authorization error from the resource server.
|
||||
*/
|
||||
+ (NSError *)resourceServerAuthorizationErrorWithCode:(NSInteger)code
|
||||
errorResponse:(nullable NSDictionary *)errorResponse
|
||||
underlyingError:(nullable NSError *)underlyingError;
|
||||
|
||||
|
||||
/*! @brief Creates a standard \NSError from an \NSHTTPURLResponse. Automatically
|
||||
populates the localized error description with the response data associated with the
|
||||
\NSHTTPURLResponse, if available.
|
||||
@param HTTPURLResponse The response which indicates an error occurred.
|
||||
@param data The response data associated with the response which should be converted to an
|
||||
@c NSString assuming a UTF-8 encoding, if available.
|
||||
@return An \NSError representing the error.
|
||||
*/
|
||||
+ (NSError *)HTTPErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPURLResponse
|
||||
data:(nullable NSData *)data;
|
||||
|
||||
/*! @brief Raises an exception with the given name as both the name, and the message.
|
||||
@param name The name of the exception.
|
||||
*/
|
||||
+ (void)raiseException:(NSString *)name;
|
||||
|
||||
/*! @brief Raises an exception with the given name and message.
|
||||
@param name The name of the exception.
|
||||
@param message The message of the exception.
|
||||
*/
|
||||
+ (void)raiseException:(NSString *)name message:(NSString *)message;
|
||||
|
||||
/*! @brief Converts an OAuth error code into an @c ::OIDErrorCodeOAuth error code.
|
||||
@param errorCode The OAuth error code.
|
||||
@discussion Returns @c ::OIDErrorCodeOAuthOther if the string is not in AppAuth's list.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
+ (OIDErrorCodeOAuth)OAuthErrorCodeFromString:(NSString *)errorCode;
|
||||
|
||||
/*! @brief Returns true if the given error domain is an OAuth error domain.
|
||||
@param errorDomain The error domain to test.
|
||||
@discussion An OAuth error domain is used for errors returned per RFC6749 sections 4.1.2.1 and
|
||||
5.2. Other errors, such as network errors can also occur but they will not have an OAuth
|
||||
error domain.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
*/
|
||||
+ (BOOL)isOAuthErrorDomain:(NSString*)errorDomain;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
172
Pods/AppAuth/Source/AppAuthCore/OIDErrorUtilities.m
generated
Normal file
172
Pods/AppAuth/Source/AppAuthCore/OIDErrorUtilities.m
generated
Normal file
@ -0,0 +1,172 @@
|
||||
/*! @file OIDErrorUtilities.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDErrorUtilities.h"
|
||||
|
||||
@implementation OIDErrorUtilities
|
||||
|
||||
+ (NSError *)errorWithCode:(OIDErrorCode)code
|
||||
underlyingError:(NSError *)underlyingError
|
||||
description:(NSString *)description {
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
if (underlyingError) {
|
||||
userInfo[NSUnderlyingErrorKey] = underlyingError;
|
||||
}
|
||||
if (description) {
|
||||
userInfo[NSLocalizedDescriptionKey] = description;
|
||||
}
|
||||
// TODO: Populate localized description based on code.
|
||||
NSError *error = [NSError errorWithDomain:OIDGeneralErrorDomain
|
||||
code:code
|
||||
userInfo:userInfo];
|
||||
return error;
|
||||
}
|
||||
|
||||
+ (BOOL)isOAuthErrorDomain:(NSString *)errorDomain {
|
||||
return errorDomain == OIDOAuthRegistrationErrorDomain
|
||||
|| errorDomain == OIDOAuthAuthorizationErrorDomain
|
||||
|| errorDomain == OIDOAuthTokenErrorDomain;
|
||||
}
|
||||
|
||||
+ (NSError *)resourceServerAuthorizationErrorWithCode:(NSInteger)code
|
||||
errorResponse:(nullable NSDictionary *)errorResponse
|
||||
underlyingError:(nullable NSError *)underlyingError {
|
||||
// builds the userInfo dictionary with the full OAuth response and other information
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
if (errorResponse) {
|
||||
userInfo[OIDOAuthErrorResponseErrorKey] = errorResponse;
|
||||
}
|
||||
if (underlyingError) {
|
||||
userInfo[NSUnderlyingErrorKey] = underlyingError;
|
||||
}
|
||||
NSError *error = [NSError errorWithDomain:OIDResourceServerAuthorizationErrorDomain
|
||||
code:code
|
||||
userInfo:userInfo];
|
||||
return error;
|
||||
}
|
||||
|
||||
+ (NSError *)OAuthErrorWithDomain:(NSString *)oAuthErrorDomain
|
||||
OAuthResponse:(NSDictionary *)errorResponse
|
||||
underlyingError:(NSError *)underlyingError {
|
||||
// not a valid OAuth error
|
||||
if (![self isOAuthErrorDomain:oAuthErrorDomain]
|
||||
|| !errorResponse
|
||||
|| !errorResponse[OIDOAuthErrorFieldError]
|
||||
|| ![errorResponse[OIDOAuthErrorFieldError] isKindOfClass:[NSString class]]) {
|
||||
return [[self class] errorWithCode:OIDErrorCodeNetworkError
|
||||
underlyingError:underlyingError
|
||||
description:underlyingError.localizedDescription];
|
||||
}
|
||||
|
||||
// builds the userInfo dictionary with the full OAuth response and other information
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
userInfo[OIDOAuthErrorResponseErrorKey] = errorResponse;
|
||||
if (underlyingError) {
|
||||
userInfo[NSUnderlyingErrorKey] = underlyingError;
|
||||
}
|
||||
|
||||
NSString *oauthErrorCodeString = errorResponse[OIDOAuthErrorFieldError];
|
||||
NSString *oauthErrorMessage = nil;
|
||||
if ([errorResponse[OIDOAuthErrorFieldErrorDescription] isKindOfClass:[NSString class]]) {
|
||||
oauthErrorMessage = errorResponse[OIDOAuthErrorFieldErrorDescription];
|
||||
} else {
|
||||
oauthErrorMessage = [errorResponse[OIDOAuthErrorFieldErrorDescription] description];
|
||||
}
|
||||
NSString *oauthErrorURI = nil;
|
||||
if ([errorResponse[OIDOAuthErrorFieldErrorURI] isKindOfClass:[NSString class]]) {
|
||||
oauthErrorURI = errorResponse[OIDOAuthErrorFieldErrorURI];
|
||||
} else {
|
||||
oauthErrorURI = [errorResponse[OIDOAuthErrorFieldErrorURI] description];
|
||||
}
|
||||
|
||||
// builds the error description, using the information supplied by the server if possible
|
||||
NSMutableString *description = [NSMutableString string];
|
||||
[description appendString:oauthErrorCodeString];
|
||||
if (oauthErrorMessage) {
|
||||
[description appendString:@": "];
|
||||
[description appendString:oauthErrorMessage];
|
||||
}
|
||||
if (oauthErrorURI) {
|
||||
if ([description length] > 0) {
|
||||
[description appendString:@" - "];
|
||||
}
|
||||
[description appendString:oauthErrorURI];
|
||||
}
|
||||
if ([description length] == 0) {
|
||||
// backup description
|
||||
[description appendFormat:@"OAuth error: %@ - https://tools.ietf.org/html/rfc6749#section-5.2",
|
||||
oauthErrorCodeString];
|
||||
}
|
||||
userInfo[NSLocalizedDescriptionKey] = description;
|
||||
|
||||
// looks up the error code based on the "error" response param
|
||||
OIDErrorCodeOAuth code = [[self class] OAuthErrorCodeFromString:oauthErrorCodeString];
|
||||
|
||||
NSError *error = [NSError errorWithDomain:oAuthErrorDomain
|
||||
code:code
|
||||
userInfo:userInfo];
|
||||
return error;
|
||||
}
|
||||
|
||||
+ (NSError *)HTTPErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPURLResponse
|
||||
data:(nullable NSData *)data {
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
if (data) {
|
||||
NSString *serverResponse =
|
||||
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
if (serverResponse) {
|
||||
userInfo[NSLocalizedDescriptionKey] = serverResponse;
|
||||
}
|
||||
}
|
||||
NSError *serverError =
|
||||
[NSError errorWithDomain:OIDHTTPErrorDomain
|
||||
code:HTTPURLResponse.statusCode
|
||||
userInfo:userInfo];
|
||||
return serverError;
|
||||
}
|
||||
|
||||
+ (OIDErrorCodeOAuth)OAuthErrorCodeFromString:(NSString *)errorCode {
|
||||
NSDictionary *errorCodes = @{
|
||||
@"invalid_request": @(OIDErrorCodeOAuthInvalidRequest),
|
||||
@"unauthorized_client": @(OIDErrorCodeOAuthUnauthorizedClient),
|
||||
@"access_denied": @(OIDErrorCodeOAuthAccessDenied),
|
||||
@"unsupported_response_type": @(OIDErrorCodeOAuthUnsupportedResponseType),
|
||||
@"invalid_scope": @(OIDErrorCodeOAuthInvalidScope),
|
||||
@"server_error": @(OIDErrorCodeOAuthServerError),
|
||||
@"temporarily_unavailable": @(OIDErrorCodeOAuthTemporarilyUnavailable),
|
||||
@"invalid_client": @(OIDErrorCodeOAuthInvalidClient),
|
||||
@"invalid_grant": @(OIDErrorCodeOAuthInvalidGrant),
|
||||
@"unsupported_grant_type": @(OIDErrorCodeOAuthUnsupportedGrantType),
|
||||
};
|
||||
NSNumber *code = errorCodes[errorCode];
|
||||
if (code) {
|
||||
return [code integerValue];
|
||||
} else {
|
||||
return OIDErrorCodeOAuthOther;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)raiseException:(NSString *)name {
|
||||
[[self class] raiseException:name message:name];
|
||||
}
|
||||
|
||||
+ (void)raiseException:(NSString *)name message:(NSString *)message {
|
||||
[NSException raise:name format:@"%@", message];
|
||||
}
|
||||
|
||||
@end
|
||||
53
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgent.h
generated
Normal file
53
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgent.h
generated
Normal file
@ -0,0 +1,53 @@
|
||||
/*! @file OIDExternalUserAgent.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@protocol OIDExternalUserAgentSession;
|
||||
@protocol OIDExternalUserAgentRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @protocol OIDExternalUserAgent
|
||||
@brief An external user-agent UI that presents displays the request to the user. Clients may
|
||||
provide custom implementations of an external user-agent to customize the way the requests
|
||||
are presented to the end user.
|
||||
*/
|
||||
@protocol OIDExternalUserAgent<NSObject>
|
||||
|
||||
/*! @brief Presents the request in the external user-agent.
|
||||
@param request The request to be presented in the external user-agent.
|
||||
@param session The @c OIDExternalUserAgentSession instance that initiates presenting the UI.
|
||||
Concrete implementations of a @c OIDExternalUserAgent may call
|
||||
resumeExternalUserAgentFlowWithURL or failExternalUserAgentFlowWithError on session to either
|
||||
resume or fail the request.
|
||||
@return YES If the request UI was successfully presented to the user.
|
||||
*/
|
||||
- (BOOL)presentExternalUserAgentRequest:(id<OIDExternalUserAgentRequest> )request
|
||||
session:(id<OIDExternalUserAgentSession>)session;
|
||||
|
||||
/*! @brief Dimisses the external user-agent and calls completion when the dismiss operation ends.
|
||||
@param animated Whether or not the dismiss operation should be animated.
|
||||
@remarks Has no effect if no UI is presented.
|
||||
@param completion The block to be called when the dismiss operations ends
|
||||
*/
|
||||
- (void)dismissExternalUserAgentAnimated:(BOOL)animated completion:(void (^)(void))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
37
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgentRequest.h
generated
Normal file
37
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgentRequest.h
generated
Normal file
@ -0,0 +1,37 @@
|
||||
/*! @file OIDExternalUserAgent.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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.
|
||||
*/
|
||||
|
||||
/*! @protocol OIDExternalUserAgent
|
||||
@brief An interface that any external user-agent request may implement to use the
|
||||
@c OIDExternalUserAgent flow.
|
||||
*/
|
||||
@protocol OIDExternalUserAgentRequest
|
||||
|
||||
/*! @brief Method to create and return the complete request URL instance.
|
||||
@return A @c NSURL instance which contains the URL to be opened in an external UI (i.e. browser)
|
||||
*/
|
||||
- (NSURL*)externalUserAgentRequestURL;
|
||||
|
||||
/*! @brief If this external user-agent request has a redirect URL, this should return its scheme.
|
||||
Since some external requests have optional callbacks (such as the end session endpoint), the
|
||||
return value of this method is nullable.
|
||||
@return A @c NSString instance that contains the scheme of a callback url, or nil if there is
|
||||
no callback url for this request.
|
||||
*/
|
||||
- (NSString*)redirectScheme;
|
||||
@end
|
||||
65
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgentSession.h
generated
Normal file
65
Pods/AppAuth/Source/AppAuthCore/OIDExternalUserAgentSession.h
generated
Normal file
@ -0,0 +1,65 @@
|
||||
/*! @file OIDExternalUserAgentSession.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 The AppAuth Authors. All Rights Reserved.
|
||||
@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.
|
||||
*/
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents an in-flight external user-agent session.
|
||||
*/
|
||||
@protocol OIDExternalUserAgentSession <NSObject>
|
||||
|
||||
/*! @brief Cancels the code flow session, invoking the request's callback with a cancelled error.
|
||||
@remarks Has no effect if called more than once, or after a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message was received.
|
||||
Will cause an error with code: @c ::OIDErrorCodeProgramCanceledAuthorizationFlow to be
|
||||
passed to the @c callback block passed to
|
||||
@c OIDAuthorizationService.presentAuthorizationRequest:presentingViewController:callback:
|
||||
*/
|
||||
- (void)cancel;
|
||||
|
||||
/*! @brief Cancels the code flow session, invoking the request's callback with a cancelled error.
|
||||
@remarks Has no effect if called more than once, or after a
|
||||
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message was received.
|
||||
Will cause an error with code: @c ::OIDErrorCodeProgramCanceledAuthorizationFlow to be
|
||||
passed to the @c callback block passed to
|
||||
@c OIDAuthorizationService.presentAuthorizationRequest:presentingViewController:callback:
|
||||
@param completion The block to be called when the cancel operation ends
|
||||
*/
|
||||
- (void)cancelWithCompletion:(nullable void (^)(void))completion;
|
||||
|
||||
/*! @brief Clients should call this method with the result of the external user-agent code flow if
|
||||
it becomes available.
|
||||
@param URL The redirect URL invoked by the server.
|
||||
@discussion When the URL represented a valid response, implementations should clean up any
|
||||
left-over UI state from the request, for example by closing the
|
||||
\SFSafariViewController or loopback HTTP listener if those were used. The completion block
|
||||
of the pending request should then be invoked.
|
||||
@remarks Has no effect if called more than once, or after a @c cancel message was received.
|
||||
@return YES if the passed URL matches the expected redirect URL and was consumed, NO otherwise.
|
||||
*/
|
||||
- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL;
|
||||
|
||||
/*! @brief @c OIDExternalUserAgent or clients should call this method when the
|
||||
external user-agent flow failed with a non-OAuth error.
|
||||
@param error The error that is the reason for the failure of this external flow.
|
||||
@remarks Has no effect if called more than once, or after a @c cancel message was received.
|
||||
*/
|
||||
- (void)failExternalUserAgentFlowWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
126
Pods/AppAuth/Source/AppAuthCore/OIDFieldMapping.h
generated
Normal file
126
Pods/AppAuth/Source/AppAuthCore/OIDFieldMapping.h
generated
Normal file
@ -0,0 +1,126 @@
|
||||
/*! @file OIDFieldMapping.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 Represents a function which transforms incoming source values into instance variable
|
||||
values.
|
||||
*/
|
||||
typedef _Nullable id(^OIDFieldMappingConversionFunction)(NSObject *_Nullable value);
|
||||
|
||||
/*! @brief Describes the mapping of a key/value pair to an iVar with an optional conversion
|
||||
function.
|
||||
*/
|
||||
@interface OIDFieldMapping : NSObject
|
||||
|
||||
/*! @brief The name of the instance variable the field should be mapped to.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *name;
|
||||
|
||||
/*! @brief The type of the instance variable.
|
||||
*/
|
||||
@property(nonatomic, readonly) Class expectedType;
|
||||
|
||||
/*! @brief An optional conversion function which specifies a transform from the incoming data to the
|
||||
instance variable value.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) OIDFieldMappingConversionFunction conversion;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithName:type:conversion:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief The designated initializer.
|
||||
@param name The name of the instance variable the field should be mapped to.
|
||||
@param type The type of the instance variable.
|
||||
@param conversion An optional conversion function which specifies a transform from the incoming
|
||||
data to the instance variable value. Used during the process performed by
|
||||
@c OIDFieldMapping.remainingParametersWithMap:parameters:instance: but not during
|
||||
encoding/decoding, since the encoded and decoded values should already be of the type
|
||||
specified by the @c type parameter.
|
||||
*/
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
type:(Class)type
|
||||
conversion:(nullable OIDFieldMappingConversionFunction)conversion
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief A convenience initializer.
|
||||
@param name The name of the instance variable the field should be mapped to.
|
||||
@param type The type of the instance variable.
|
||||
*/
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
type:(Class)type;
|
||||
|
||||
/*! @brief Performs a mapping of key/value pairs in an incoming parameters dictionary to instance
|
||||
variables, returning a dictionary of parameter key/values which didn't map to instance
|
||||
variables.
|
||||
@param map A mapping of incoming keys to instance variables.
|
||||
@param parameters Incoming key value pairs to map to an instance's variables.
|
||||
@param instance The instance whose variables should be set based on the mapping.
|
||||
@return A dictionary of parameter key/values which didn't map to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, NSObject<NSCopying> *> *)remainingParametersWithMap:
|
||||
(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters
|
||||
instance:(id)instance;
|
||||
|
||||
/*! @brief This helper method for @c NSCoding implementations performs a serialization of fields
|
||||
defined in a field mapping.
|
||||
@param aCoder An @c NSCoder instance to serialize instance variable values to.
|
||||
@param map A mapping of keys to instance variables.
|
||||
@param instance The instance whose variables should be serialized based on the mapping.
|
||||
*/
|
||||
+ (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
map:(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
instance:(id)instance;
|
||||
|
||||
/*! @brief This helper method for @c NSCoding implementations performs a deserialization of
|
||||
fields defined in a field mapping.
|
||||
@param aCoder An @c NSCoder instance from which to deserialize instance variable values from.
|
||||
@param map A mapping of keys to instance variables.
|
||||
@param instance The instance whose variables should be deserialized based on the mapping.
|
||||
*/
|
||||
+ (void)decodeWithCoder:(NSCoder *)aCoder
|
||||
map:(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
instance:(id)instance;
|
||||
|
||||
/*! @brief Returns an @c NSSet of classes suitable for deserializing JSON content in an
|
||||
@c NSSecureCoding context.
|
||||
*/
|
||||
+ (NSSet *)JSONTypes;
|
||||
|
||||
/*! @brief Returns a function for converting an @c NSString to an @c NSURL.
|
||||
*/
|
||||
+ (OIDFieldMappingConversionFunction)URLConversion;
|
||||
|
||||
/*! @brief Returns a function for converting an @c NSNumber number of seconds from now to an
|
||||
@c NSDate.
|
||||
*/
|
||||
+ (OIDFieldMappingConversionFunction)dateSinceNowConversion;
|
||||
|
||||
/*! @brief Returns a function for converting an @c NSNumber representing a unix time stamp to an
|
||||
@c NSDate.
|
||||
*/
|
||||
+ (OIDFieldMappingConversionFunction)dateEpochConversion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
132
Pods/AppAuth/Source/AppAuthCore/OIDFieldMapping.m
generated
Normal file
132
Pods/AppAuth/Source/AppAuthCore/OIDFieldMapping.m
generated
Normal file
@ -0,0 +1,132 @@
|
||||
/*! @file OIDFieldMapping.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDFieldMapping.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
|
||||
@implementation OIDFieldMapping
|
||||
|
||||
- (nonnull instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithName:type:conversion:))
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
type:(Class)type {
|
||||
return [self initWithName:name type:type conversion:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
type:(Class)type
|
||||
conversion:(nullable OIDFieldMappingConversionFunction)conversion {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_name = [name copy];
|
||||
_expectedType = type;
|
||||
_conversion = conversion;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, NSObject<NSCopying> *> *)remainingParametersWithMap:
|
||||
(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters
|
||||
instance:(id)instance {
|
||||
NSMutableDictionary *additionalParameters = [NSMutableDictionary dictionary];
|
||||
for (NSString *key in parameters) {
|
||||
NSObject<NSCopying> *value = [parameters[key] copy];
|
||||
OIDFieldMapping *mapping = map[key];
|
||||
// If the field doesn't appear in the mapping, we add it to the additional parameters
|
||||
// dictionary.
|
||||
if (!mapping) {
|
||||
additionalParameters[key] = value;
|
||||
continue;
|
||||
}
|
||||
// If the field mapping specifies a conversion function, apply the conversion to the value.
|
||||
if (mapping.conversion) {
|
||||
value = mapping.conversion(value);
|
||||
}
|
||||
// Check the type of the value and make sure it matches the type we expected. If it doesn't we
|
||||
// add the value to the additional parameters dictionary but don't assign the instance variable.
|
||||
if (![value isKindOfClass:mapping.expectedType]) {
|
||||
additionalParameters[key] = value;
|
||||
continue;
|
||||
}
|
||||
// Assign the instance variable.
|
||||
[instance setValue:value forKey:mapping.name];
|
||||
}
|
||||
return additionalParameters;
|
||||
}
|
||||
|
||||
+ (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
map:(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
instance:(id)instance {
|
||||
for (NSString *key in map) {
|
||||
id value = [instance valueForKey:map[key].name];
|
||||
[aCoder encodeObject:value forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)decodeWithCoder:(NSCoder *)aCoder
|
||||
map:(NSDictionary<NSString *, OIDFieldMapping *> *)map
|
||||
instance:(id)instance {
|
||||
for (NSString *key in map) {
|
||||
OIDFieldMapping *mapping = map[key];
|
||||
id value = [aCoder decodeObjectOfClass:mapping.expectedType forKey:key];
|
||||
[instance setValue:value forKey:mapping.name];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSSet *)JSONTypes {
|
||||
return [NSSet setWithArray:@[
|
||||
[NSDictionary class],
|
||||
[NSArray class],
|
||||
[NSString class],
|
||||
[NSNumber class]
|
||||
]];
|
||||
}
|
||||
|
||||
+ (OIDFieldMappingConversionFunction)URLConversion {
|
||||
return ^id _Nullable(NSObject *_Nullable value) {
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
return [NSURL URLWithString:(NSString *)value];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
+ (OIDFieldMappingConversionFunction)dateSinceNowConversion {
|
||||
return ^id _Nullable(NSObject *_Nullable value) {
|
||||
if (![value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
NSNumber *valueAsNumber = (NSNumber *)value;
|
||||
return [NSDate dateWithTimeIntervalSinceNow:[valueAsNumber longLongValue]];
|
||||
};
|
||||
}
|
||||
|
||||
+ (OIDFieldMappingConversionFunction)dateEpochConversion {
|
||||
return ^id _Nullable(NSObject *_Nullable value) {
|
||||
if (![value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
NSNumber *valueAsNumber = (NSNumber *) value;
|
||||
return [NSDate dateWithTimeIntervalSince1970:[valueAsNumber longLongValue]];
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
40
Pods/AppAuth/Source/AppAuthCore/OIDGrantTypes.h
generated
Normal file
40
Pods/AppAuth/Source/AppAuthCore/OIDGrantTypes.h
generated
Normal file
@ -0,0 +1,40 @@
|
||||
/*! @file OIDGrantTypes.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
/*! @brief For exchanging an authorization code for an access token.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
extern NSString *const OIDGrantTypeAuthorizationCode;
|
||||
|
||||
/*! @brief For refreshing an access token with a refresh token.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-6
|
||||
*/
|
||||
extern NSString *const OIDGrantTypeRefreshToken;
|
||||
|
||||
/*! @brief For obtaining an access token with a username and password.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.3.2
|
||||
*/
|
||||
extern NSString *const OIDGrantTypePassword;
|
||||
|
||||
/*! @brief For obtaining an access token from the token endpoint using client credentials.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.2.1
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.4.2
|
||||
*/
|
||||
extern NSString *const OIDGrantTypeClientCredentials;
|
||||
27
Pods/AppAuth/Source/AppAuthCore/OIDGrantTypes.m
generated
Normal file
27
Pods/AppAuth/Source/AppAuthCore/OIDGrantTypes.m
generated
Normal file
@ -0,0 +1,27 @@
|
||||
/*! @file OIDGrantTypes.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDGrantTypes.h"
|
||||
|
||||
NSString *const OIDGrantTypeAuthorizationCode = @"authorization_code";
|
||||
|
||||
NSString *const OIDGrantTypeRefreshToken = @"refresh_token";
|
||||
|
||||
NSString *const OIDGrantTypePassword = @"password";
|
||||
|
||||
NSString *const OIDGrantTypeClientCredentials = @"client_credentials";
|
||||
91
Pods/AppAuth/Source/AppAuthCore/OIDIDToken.h
generated
Normal file
91
Pods/AppAuth/Source/AppAuthCore/OIDIDToken.h
generated
Normal file
@ -0,0 +1,91 @@
|
||||
/*! @file OIDIDToken.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 Google Inc. All Rights Reserved.
|
||||
@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 A convenience class that parses an ID Token and extracts the claims _but does not_
|
||||
verify its signature. AppAuth only supports the OpenID Code flow, meaning ID Tokens
|
||||
received by AppAuth are sent from the token endpoint on a TLS protected channel,
|
||||
offering some assurances as to the origin of the token. You may wish to additionally
|
||||
verify the ID Token signature using a JWT signature verification library of your
|
||||
choosing.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
@see https://tools.ietf.org/html/rfc7519
|
||||
@see https://jwt.io/
|
||||
*/
|
||||
@interface OIDIDToken : NSObject
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithAuthorizationResponse:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Parses the given ID Token string.
|
||||
@param idToken The ID Token spring.
|
||||
*/
|
||||
- (nullable instancetype)initWithIDTokenString:(NSString *)idToken;
|
||||
|
||||
/*! @brief The header JWT values.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDictionary *header;
|
||||
|
||||
/*! @brief All ID Token claims.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDictionary *claims;
|
||||
|
||||
/*! @brief Issuer Identifier for the Issuer of the response.
|
||||
@remarks iss
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *issuer;
|
||||
|
||||
/*! @brief Subject Identifier.
|
||||
@remarks sub
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *subject;
|
||||
|
||||
/*! @brief Audience(s) that this ID Token is intended for.
|
||||
@remarks aud
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray *audience;
|
||||
|
||||
/*! @brief Expiration time on or after which the ID Token MUST NOT be accepted for processing.
|
||||
@remarks exp
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDate *expiresAt;
|
||||
|
||||
/*! @brief Time at which the JWT was issued.
|
||||
@remarks iat
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDate *issuedAt;
|
||||
|
||||
/*! @brief String value used to associate a Client session with an ID Token, and to mitigate replay
|
||||
attacks.
|
||||
@remarks nonce
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *nonce;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
149
Pods/AppAuth/Source/AppAuthCore/OIDIDToken.m
generated
Normal file
149
Pods/AppAuth/Source/AppAuthCore/OIDIDToken.m
generated
Normal file
@ -0,0 +1,149 @@
|
||||
/*! @file OIDIDToken.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2017 Google Inc. All Rights Reserved.
|
||||
@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 "OIDIDToken.h"
|
||||
|
||||
/*! Field keys associated with an ID Token. */
|
||||
static NSString *const kIssKey = @"iss";
|
||||
static NSString *const kSubKey = @"sub";
|
||||
static NSString *const kAudKey = @"aud";
|
||||
static NSString *const kExpKey = @"exp";
|
||||
static NSString *const kIatKey = @"iat";
|
||||
static NSString *const kNonceKey = @"nonce";
|
||||
|
||||
#import "OIDFieldMapping.h"
|
||||
|
||||
@implementation OIDIDToken
|
||||
|
||||
- (instancetype)initWithIDTokenString:(NSString *)idToken {
|
||||
self = [super init];
|
||||
NSArray *sections = [idToken componentsSeparatedByString:@"."];
|
||||
|
||||
// The header and claims sections are required.
|
||||
if (sections.count <= 1) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_header = [[self class] parseJWTSection:sections[0]];
|
||||
_claims = [[self class] parseJWTSection:sections[1]];
|
||||
if (!_header || !_claims) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[OIDFieldMapping remainingParametersWithMap:[[self class] fieldMap]
|
||||
parameters:_claims
|
||||
instance:self];
|
||||
|
||||
// Required fields.
|
||||
if (!_issuer || !_audience || !_subject || !_expiresAt || !_issuedAt) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*! @brief Returns a mapping of incoming parameters to instance variables.
|
||||
@return A mapping of incoming parameters to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, OIDFieldMapping *> *)fieldMap {
|
||||
static NSMutableDictionary<NSString *, OIDFieldMapping *> *fieldMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
fieldMap = [NSMutableDictionary dictionary];
|
||||
|
||||
fieldMap[kIssKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_issuer"
|
||||
type:[NSURL class]
|
||||
conversion:[OIDFieldMapping URLConversion]];
|
||||
fieldMap[kSubKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_subject" type:[NSString class]];
|
||||
fieldMap[kAudKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_audience"
|
||||
type:[NSArray class]
|
||||
conversion:^id _Nullable(NSObject *_Nullable value) {
|
||||
if ([value isKindOfClass:[NSArray class]]) {
|
||||
return value;
|
||||
}
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
return @[value];
|
||||
}
|
||||
return nil;
|
||||
}];
|
||||
fieldMap[kExpKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_expiresAt"
|
||||
type:[NSDate class]
|
||||
conversion:^id _Nullable(NSObject *_Nullable value) {
|
||||
if (![value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
NSNumber *valueAsNumber = (NSNumber *)value;
|
||||
return [NSDate dateWithTimeIntervalSince1970:valueAsNumber.longLongValue];
|
||||
}];
|
||||
fieldMap[kIatKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_issuedAt"
|
||||
type:[NSDate class]
|
||||
conversion:^id _Nullable(NSObject *_Nullable value) {
|
||||
if (![value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
NSNumber *valueAsNumber = (NSNumber *)value;
|
||||
return [NSDate dateWithTimeIntervalSince1970:valueAsNumber.longLongValue];
|
||||
}];
|
||||
fieldMap[kNonceKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_nonce" type:[NSString class]];
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)parseJWTSection:(NSString *)sectionString {
|
||||
NSData *decodedData = [[self class] base64urlNoPaddingDecode:sectionString];
|
||||
|
||||
// Parses JSON.
|
||||
NSError *error;
|
||||
id object = [NSJSONSerialization JSONObjectWithData:decodedData options:0 error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error %@ parsing token payload %@", error, sectionString);
|
||||
}
|
||||
if ([object isKindOfClass:[NSDictionary class]]) {
|
||||
return (NSDictionary *)object;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSData *)base64urlNoPaddingDecode:(NSString *)base64urlNoPaddingString {
|
||||
NSMutableString *body = [base64urlNoPaddingString mutableCopy];
|
||||
|
||||
// Converts base64url to base64.
|
||||
NSRange range = NSMakeRange(0, base64urlNoPaddingString.length);
|
||||
[body replaceOccurrencesOfString:@"-" withString:@"+" options:NSLiteralSearch range:range];
|
||||
[body replaceOccurrencesOfString:@"_" withString:@"/" options:NSLiteralSearch range:range];
|
||||
|
||||
// Converts base64 no padding to base64 with padding
|
||||
while (body.length % 4 != 0) {
|
||||
[body appendString:@"="];
|
||||
}
|
||||
|
||||
// Decodes base64 string.
|
||||
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:body options:0];
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
141
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationRequest.h
generated
Normal file
141
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationRequest.h
generated
Normal file
@ -0,0 +1,141 @@
|
||||
/*! @file OIDRegistrationRequest.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthorizationResponse;
|
||||
@class OIDServiceConfiguration;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents a registration request.
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest
|
||||
*/
|
||||
@interface OIDRegistrationRequest : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The service's configuration.
|
||||
@remarks This configuration specifies how to connect to a particular OAuth provider.
|
||||
Configurations may be created manually, or via an OpenID Connect Discovery Document.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDServiceConfiguration *configuration;
|
||||
|
||||
/*! @brief The initial access token to access the Client Registration Endpoint
|
||||
(if required by the OpenID Provider).
|
||||
@remarks OAuth 2.0 Access Token optionally issued by an Authorization Server granting
|
||||
access to its Client Registration Endpoint. This token (if required) is
|
||||
provisioned out of band.
|
||||
@see Section 3 of OpenID Connect Dynamic Client Registration 1.0
|
||||
https://openid.net/specs/openid-connect-registration-1_0.html#ClientRegistration
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *initialAccessToken;
|
||||
|
||||
/*! @brief The application type to register, will always be 'native'.
|
||||
@remarks application_type
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *applicationType;
|
||||
|
||||
/*! @brief The client's redirect URI's.
|
||||
@remarks redirect_uris
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray<NSURL *> *redirectURIs;
|
||||
|
||||
/*! @brief The response types to register for usage by this client.
|
||||
@remarks response_types
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#Authentication
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *responseTypes;
|
||||
|
||||
/*! @brief The grant types to register for usage by this client.
|
||||
@remarks grant_types
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *grantTypes;
|
||||
|
||||
/*! @brief The subject type to to request.
|
||||
@remarks subject_type
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *subjectType;
|
||||
|
||||
/*! @brief The client authentication method to use at the token endpoint.
|
||||
@remarks token_endpoint_auth_method
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *tokenEndpointAuthenticationMethod;
|
||||
|
||||
/*! @brief The client's additional token request parameters.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithConfiguration
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Create a Client Registration Request to an OpenID Provider that supports open Dynamic
|
||||
Registration.
|
||||
@param configuration The service's configuration.
|
||||
@param redirectURIs The redirect URIs to register for the client.
|
||||
@param responseTypes The response types to register for the client.
|
||||
@param grantTypes The grant types to register for the client.
|
||||
@param subjectType The subject type to register for the client.
|
||||
@param tokenEndpointAuthMethod The token endpoint authentication method to register for the
|
||||
client.
|
||||
@param additionalParameters The client's additional registration request parameters.
|
||||
*/
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
redirectURIs:(NSArray<NSURL *> *)redirectURIs
|
||||
responseTypes:(nullable NSArray<NSString *> *)responseTypes
|
||||
grantTypes:(nullable NSArray<NSString *> *)grantTypes
|
||||
subjectType:(nullable NSString *)subjectType
|
||||
tokenEndpointAuthMethod:(nullable NSString *)tokenEndpointAuthMethod
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param configuration The service's configuration.
|
||||
@param redirectURIs The redirect URIs to register for the client.
|
||||
@param responseTypes The response types to register for the client.
|
||||
@param grantTypes The grant types to register for the client.
|
||||
@param subjectType The subject type to register for the client.
|
||||
@param tokenEndpointAuthMethod The token endpoint authentication method to register for the
|
||||
client.
|
||||
@param initialAccessToken The initial access token to access the Client Registration Endpoint
|
||||
(if required by the OpenID Provider).
|
||||
@param additionalParameters The client's additional registration request parameters.
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#ClientRegistration
|
||||
*/
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
redirectURIs:(NSArray<NSURL *> *)redirectURIs
|
||||
responseTypes:(nullable NSArray<NSString *> *)responseTypes
|
||||
grantTypes:(nullable NSArray<NSString *> *)grantTypes
|
||||
subjectType:(nullable NSString *)subjectType
|
||||
tokenEndpointAuthMethod:(nullable NSString *)tokenEndpointAuthMethod
|
||||
initialAccessToken:(nullable NSString *)initialAccessToken
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Constructs an @c NSURLRequest representing the registration request.
|
||||
@return An @c NSURLRequest representing the registration request.
|
||||
*/
|
||||
- (NSURLRequest *)URLRequest;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
248
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationRequest.m
generated
Normal file
248
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationRequest.m
generated
Normal file
@ -0,0 +1,248 @@
|
||||
/*! @file OIDRegistrationRequest.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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 "OIDRegistrationRequest.h"
|
||||
|
||||
#import "OIDClientMetadataParameters.h"
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
|
||||
/*! @brief The key for the @c configuration property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kConfigurationKey = @"configuration";
|
||||
|
||||
/*! @brief The key for the @c initialAccessToken property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kInitialAccessToken = @"initial_access_token";
|
||||
|
||||
/*! @brief Key used to encode the @c redirectURIs property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRedirectURIsKey = @"redirect_uris";
|
||||
|
||||
/*! @brief The key for the @c responseTypes property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kResponseTypesKey = @"response_types";
|
||||
|
||||
/*! @brief Key used to encode the @c grantType property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kGrantTypesKey = @"grant_types";
|
||||
|
||||
/*! @brief Key used to encode the @c subjectType property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kSubjectTypeKey = @"subject_type";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for
|
||||
@c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
@implementation OIDRegistrationRequest
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(
|
||||
@selector(initWithConfiguration:
|
||||
redirectURIs:
|
||||
responseTypes:
|
||||
grantTypes:
|
||||
subjectType:
|
||||
tokenEndpointAuthMethod:
|
||||
additionalParameters:)
|
||||
)
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
redirectURIs:(NSArray<NSURL *> *)redirectURIs
|
||||
responseTypes:(nullable NSArray<NSString *> *)responseTypes
|
||||
grantTypes:(nullable NSArray<NSString *> *)grantTypes
|
||||
subjectType:(nullable NSString *)subjectType
|
||||
tokenEndpointAuthMethod:(nullable NSString *)tokenEndpointAuthenticationMethod
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
return [self initWithConfiguration:configuration
|
||||
redirectURIs:redirectURIs
|
||||
responseTypes:responseTypes
|
||||
grantTypes:grantTypes
|
||||
subjectType:subjectType
|
||||
tokenEndpointAuthMethod:tokenEndpointAuthenticationMethod
|
||||
initialAccessToken:nil
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
redirectURIs:(NSArray<NSURL *> *)redirectURIs
|
||||
responseTypes:(nullable NSArray<NSString *> *)responseTypes
|
||||
grantTypes:(nullable NSArray<NSString *> *)grantTypes
|
||||
subjectType:(nullable NSString *)subjectType
|
||||
tokenEndpointAuthMethod:(nullable NSString *)tokenEndpointAuthenticationMethod
|
||||
initialAccessToken:(nullable NSString *)initialAccessToken
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configuration = [configuration copy];
|
||||
_initialAccessToken = [initialAccessToken copy];
|
||||
_redirectURIs = [redirectURIs copy];
|
||||
_responseTypes = [responseTypes copy];
|
||||
_grantTypes = [grantTypes copy];
|
||||
_subjectType = [subjectType copy];
|
||||
_tokenEndpointAuthenticationMethod = [tokenEndpointAuthenticationMethod copy];
|
||||
_additionalParameters =
|
||||
[[NSDictionary alloc] initWithDictionary:additionalParameters copyItems:YES];
|
||||
|
||||
_applicationType = OIDApplicationTypeNative;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDServiceConfiguration *configuration =
|
||||
[aDecoder decodeObjectOfClass:[OIDServiceConfiguration class]
|
||||
forKey:kConfigurationKey];
|
||||
NSString *initialAccessToken = [aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kInitialAccessToken];
|
||||
NSArray<NSURL *> *redirectURIs = [aDecoder decodeObjectOfClass:[NSArray<NSURL *> class]
|
||||
forKey:kRedirectURIsKey];
|
||||
NSArray<NSString *> *responseTypes = [aDecoder decodeObjectOfClass:[NSArray<NSString *> class]
|
||||
forKey:kResponseTypesKey];
|
||||
NSArray<NSString *> *grantTypes = [aDecoder decodeObjectOfClass:[NSArray<NSString *> class]
|
||||
forKey:kGrantTypesKey];
|
||||
NSString *subjectType = [aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:kSubjectTypeKey];
|
||||
NSString *tokenEndpointAuthenticationMethod =
|
||||
[aDecoder decodeObjectOfClass:[NSString class]
|
||||
forKey:OIDTokenEndpointAuthenticationMethodParam];
|
||||
NSSet *additionalParameterCodingClasses = [NSSet setWithArray:@[ [NSDictionary class],
|
||||
[NSString class] ]];
|
||||
NSDictionary *additionalParameters =
|
||||
[aDecoder decodeObjectOfClasses:additionalParameterCodingClasses
|
||||
forKey:kAdditionalParametersKey];
|
||||
self = [self initWithConfiguration:configuration
|
||||
redirectURIs:redirectURIs
|
||||
responseTypes:responseTypes
|
||||
grantTypes:grantTypes
|
||||
subjectType:subjectType
|
||||
tokenEndpointAuthMethod:tokenEndpointAuthenticationMethod
|
||||
initialAccessToken:initialAccessToken
|
||||
additionalParameters:additionalParameters];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_configuration forKey:kConfigurationKey];
|
||||
[aCoder encodeObject:_initialAccessToken forKey:kInitialAccessToken];
|
||||
[aCoder encodeObject:_redirectURIs forKey:kRedirectURIsKey];
|
||||
[aCoder encodeObject:_responseTypes forKey:kResponseTypesKey];
|
||||
[aCoder encodeObject:_grantTypes forKey:kGrantTypesKey];
|
||||
[aCoder encodeObject:_subjectType forKey:kSubjectTypeKey];
|
||||
[aCoder encodeObject:_tokenEndpointAuthenticationMethod
|
||||
forKey:OIDTokenEndpointAuthenticationMethodParam];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
NSURLRequest *request = [self URLRequest];
|
||||
NSString *requestBody = [[NSString alloc] initWithData:request.HTTPBody
|
||||
encoding:NSUTF8StringEncoding];
|
||||
return [NSString stringWithFormat:@"<%@: %p, request: <URL: %@, HTTPBody: %@>>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
request.URL,
|
||||
requestBody];
|
||||
}
|
||||
|
||||
- (NSURLRequest *)URLRequest {
|
||||
static NSString *const kHTTPPost = @"POST";
|
||||
static NSString *const kBearer = @"Bearer";
|
||||
static NSString *const kHTTPContentTypeHeaderKey = @"Content-Type";
|
||||
static NSString *const kHTTPContentTypeHeaderValue = @"application/json";
|
||||
static NSString *const kHTTPAuthorizationHeaderKey = @"Authorization";
|
||||
|
||||
NSData *postBody = [self JSONString];
|
||||
if (!postBody) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURL *registrationRequestURL = _configuration.registrationEndpoint;
|
||||
NSMutableURLRequest *URLRequest =
|
||||
[[NSURLRequest requestWithURL:registrationRequestURL] mutableCopy];
|
||||
URLRequest.HTTPMethod = kHTTPPost;
|
||||
[URLRequest setValue:kHTTPContentTypeHeaderValue forHTTPHeaderField:kHTTPContentTypeHeaderKey];
|
||||
if (_initialAccessToken) {
|
||||
NSString *value = [NSString stringWithFormat:@"%@ %@", kBearer, _initialAccessToken];
|
||||
[URLRequest setValue:value forHTTPHeaderField:kHTTPAuthorizationHeaderKey];
|
||||
}
|
||||
URLRequest.HTTPBody = postBody;
|
||||
return URLRequest;
|
||||
}
|
||||
|
||||
- (NSData *)JSONString {
|
||||
// Dictionary with several kay/value pairs and the above array of arrays
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
NSMutableArray<NSString *> *redirectURIStrings =
|
||||
[NSMutableArray arrayWithCapacity:[_redirectURIs count]];
|
||||
for (id obj in _redirectURIs) {
|
||||
[redirectURIStrings addObject:[obj absoluteString]];
|
||||
}
|
||||
dict[OIDRedirectURIsParam] = redirectURIStrings;
|
||||
dict[OIDApplicationTypeParam] = _applicationType;
|
||||
|
||||
if (_additionalParameters) {
|
||||
// Add any additional parameters first to allow them
|
||||
// to be overwritten by instance values
|
||||
[dict addEntriesFromDictionary:_additionalParameters];
|
||||
}
|
||||
if (_responseTypes) {
|
||||
dict[OIDResponseTypesParam] = _responseTypes;
|
||||
}
|
||||
if (_grantTypes) {
|
||||
dict[OIDGrantTypesParam] = _grantTypes;
|
||||
}
|
||||
if (_subjectType) {
|
||||
dict[OIDSubjectTypeParam] = _subjectType;
|
||||
}
|
||||
if (_tokenEndpointAuthenticationMethod) {
|
||||
dict[OIDTokenEndpointAuthenticationMethodParam] = _tokenEndpointAuthenticationMethod;
|
||||
}
|
||||
|
||||
NSError *error;
|
||||
NSData *json = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&error];
|
||||
if (json == nil || error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@end
|
||||
126
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationResponse.h
generated
Normal file
126
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationResponse.h
generated
Normal file
@ -0,0 +1,126 @@
|
||||
/*! @file OIDRegistrationResponse.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDRegistrationRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Parameter name for the client id.
|
||||
*/
|
||||
extern NSString *const OIDClientIDParam;
|
||||
|
||||
/*! @brief Parameter name for the client id issuance timestamp.
|
||||
*/
|
||||
extern NSString *const OIDClientIDIssuedAtParam;
|
||||
|
||||
/*! @brief Parameter name for the client secret.
|
||||
*/
|
||||
extern NSString *const OIDClientSecretParam;
|
||||
|
||||
/*! @brief Parameter name for the client secret expiration time.
|
||||
*/
|
||||
extern NSString *const OIDClientSecretExpirestAtParam;
|
||||
|
||||
/*! @brief Parameter name for the registration access token.
|
||||
*/
|
||||
extern NSString *const OIDRegistrationAccessTokenParam;
|
||||
|
||||
/*! @brief Parameter name for the client configuration URI.
|
||||
*/
|
||||
extern NSString *const OIDRegistrationClientURIParam;
|
||||
|
||||
/*! @brief Represents a registration response.
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@interface OIDRegistrationResponse : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The request which was serviced.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDRegistrationRequest *request;
|
||||
|
||||
/*! @brief The registered client identifier.
|
||||
@remarks client_id
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *clientID;
|
||||
|
||||
/*! @brief Timestamp of when the client identifier was issued, if provided.
|
||||
@remarks client_id_issued_at
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDate *clientIDIssuedAt;
|
||||
|
||||
/*! @brief TThe client secret, which is part of the client credentials, if provided.
|
||||
@remarks client_secret
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *clientSecret;
|
||||
|
||||
/*! @brief Timestamp of when the client credentials expires, if provided.
|
||||
@remarks client_secret_expires_at
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDate *clientSecretExpiresAt;
|
||||
|
||||
/*! @brief Client registration access token that can be used for subsequent operations upon the
|
||||
client registration.
|
||||
@remarks registration_access_token
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *registrationAccessToken;
|
||||
|
||||
/*! @brief Location of the client configuration endpoint, if provided.
|
||||
@remarks registration_client_uri
|
||||
@see https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *registrationClientURI;
|
||||
|
||||
/*! @brief Client authentication method to use at the token endpoint, if provided.
|
||||
@remarks token_endpoint_auth_method
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *tokenEndpointAuthenticationMethod;
|
||||
|
||||
/*! @brief Additional parameters returned from the token server.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSObject <NSCopying> *>
|
||||
*additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithRequest
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param request The serviced request.
|
||||
@param parameters The decoded parameters returned from the Authorization Server.
|
||||
@remarks Known parameters are extracted from the @c parameters parameter and the normative
|
||||
properties are populated. Non-normative parameters are placed in the
|
||||
@c #additionalParameters dictionary.
|
||||
*/
|
||||
- (instancetype)initWithRequest:(OIDRegistrationRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject <NSCopying> *> *)parameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
164
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationResponse.m
generated
Normal file
164
Pods/AppAuth/Source/AppAuthCore/OIDRegistrationResponse.m
generated
Normal file
@ -0,0 +1,164 @@
|
||||
/*! @file OIDRegistrationResponse.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2016 The AppAuth for iOS Authors. All Rights Reserved.
|
||||
@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 "OIDRegistrationResponse.h"
|
||||
|
||||
#import "OIDClientMetadataParameters.h"
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDFieldMapping.h"
|
||||
#import "OIDRegistrationRequest.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
|
||||
NSString *const OIDClientIDParam = @"client_id";
|
||||
NSString *const OIDClientIDIssuedAtParam = @"client_id_issued_at";
|
||||
NSString *const OIDClientSecretParam = @"client_secret";
|
||||
NSString *const OIDClientSecretExpirestAtParam = @"client_secret_expires_at";
|
||||
NSString *const OIDRegistrationAccessTokenParam = @"registration_access_token";
|
||||
NSString *const OIDRegistrationClientURIParam = @"registration_client_uri";
|
||||
|
||||
/*! @brief Key used to encode the @c request property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRequestKey = @"request";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
@implementation OIDRegistrationResponse
|
||||
|
||||
/*! @brief Returns a mapping of incoming parameters to instance variables.
|
||||
@return A mapping of incoming parameters to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, OIDFieldMapping *> *)fieldMap {
|
||||
static NSMutableDictionary<NSString *, OIDFieldMapping *> *fieldMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
fieldMap = [NSMutableDictionary dictionary];
|
||||
fieldMap[OIDClientIDParam] = [[OIDFieldMapping alloc] initWithName:@"_clientID"
|
||||
type:[NSString class]];
|
||||
fieldMap[OIDClientIDIssuedAtParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_clientIDIssuedAt"
|
||||
type:[NSDate class]
|
||||
conversion:[OIDFieldMapping dateEpochConversion]];
|
||||
fieldMap[OIDClientSecretParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_clientSecret"
|
||||
type:[NSString class]];
|
||||
fieldMap[OIDClientSecretExpirestAtParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_clientSecretExpiresAt"
|
||||
type:[NSDate class]
|
||||
conversion:[OIDFieldMapping dateEpochConversion]];
|
||||
fieldMap[OIDRegistrationAccessTokenParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_registrationAccessToken"
|
||||
type:[NSString class]];
|
||||
fieldMap[OIDRegistrationClientURIParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_registrationClientURI"
|
||||
type:[NSURL class]
|
||||
conversion:[OIDFieldMapping URLConversion]];
|
||||
fieldMap[OIDTokenEndpointAuthenticationMethodParam] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_tokenEndpointAuthenticationMethod"
|
||||
type:[NSString class]];
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (nonnull instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithRequest:parameters:))
|
||||
|
||||
- (instancetype)initWithRequest:(OIDRegistrationRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject <NSCopying> *> *)parameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
NSDictionary<NSString *, NSObject <NSCopying> *> *additionalParameters =
|
||||
[OIDFieldMapping remainingParametersWithMap:[[self class] fieldMap]
|
||||
parameters:parameters
|
||||
instance:self];
|
||||
_additionalParameters = additionalParameters;
|
||||
|
||||
if ((_clientSecret && !_clientSecretExpiresAt)
|
||||
|| (!!_registrationClientURI != !!_registrationAccessToken)) {
|
||||
// If client_secret is issued, client_secret_expires_at is REQUIRED,
|
||||
// and the response MUST contain "[...] both a Client Configuration Endpoint
|
||||
// and a Registration Access Token or neither of them"
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDRegistrationRequest *request = [aDecoder decodeObjectOfClass:[OIDRegistrationRequest class]
|
||||
forKey:kRequestKey];
|
||||
self = [self initWithRequest:request
|
||||
parameters:@{}];
|
||||
if (self) {
|
||||
[OIDFieldMapping decodeWithCoder:aDecoder
|
||||
map:[[self class] fieldMap]
|
||||
instance:self];
|
||||
_additionalParameters = [aDecoder decodeObjectOfClasses:[OIDFieldMapping JSONTypes]
|
||||
forKey:kAdditionalParametersKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[OIDFieldMapping encodeWithCoder:aCoder map:[[self class] fieldMap] instance:self];
|
||||
[aCoder encodeObject:_request forKey:kRequestKey];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, clientID: \"%@\", clientIDIssuedAt: %@, "
|
||||
"clientSecret: %@, clientSecretExpiresAt: \"%@\", "
|
||||
"registrationAccessToken: \"%@\", "
|
||||
"registrationClientURI: \"%@\", "
|
||||
"additionalParameters: %@, request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
_clientID,
|
||||
_clientIDIssuedAt,
|
||||
[OIDTokenUtilities redact:_clientSecret],
|
||||
_clientSecretExpiresAt,
|
||||
[OIDTokenUtilities redact:_registrationAccessToken],
|
||||
_registrationClientURI,
|
||||
_additionalParameters,
|
||||
_request];
|
||||
}
|
||||
|
||||
@end
|
||||
31
Pods/AppAuth/Source/AppAuthCore/OIDResponseTypes.h
generated
Normal file
31
Pods/AppAuth/Source/AppAuthCore/OIDResponseTypes.h
generated
Normal file
@ -0,0 +1,31 @@
|
||||
/*! @file OIDResponseTypes.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
/*! @brief A constant for the standard OAuth2 Response Type of 'code'.
|
||||
*/
|
||||
extern NSString *const OIDResponseTypeCode;
|
||||
|
||||
/*! @brief A constant for the standard OAuth2 Response Type of 'token'.
|
||||
*/
|
||||
extern NSString *const OIDResponseTypeToken;
|
||||
|
||||
/*! @brief A constant for the standard OAuth2 Response Type of 'id_token'.
|
||||
*/
|
||||
extern NSString *const OIDResponseTypeIDToken;
|
||||
25
Pods/AppAuth/Source/AppAuthCore/OIDResponseTypes.m
generated
Normal file
25
Pods/AppAuth/Source/AppAuthCore/OIDResponseTypes.m
generated
Normal file
@ -0,0 +1,25 @@
|
||||
/*! @file OIDResponseTypes.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDResponseTypes.h"
|
||||
|
||||
NSString *const OIDResponseTypeCode = @"code";
|
||||
|
||||
NSString *const OIDResponseTypeToken = @"token";
|
||||
|
||||
NSString *const OIDResponseTypeIDToken = @"id_token";
|
||||
48
Pods/AppAuth/Source/AppAuthCore/OIDScopeUtilities.h
generated
Normal file
48
Pods/AppAuth/Source/AppAuthCore/OIDScopeUtilities.h
generated
Normal file
@ -0,0 +1,48 @@
|
||||
/*! @file OIDScopeUtilities.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 Provides convenience methods for dealing with scope strings.
|
||||
*/
|
||||
@interface OIDScopeUtilities : NSObject
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. This class should not be initialized.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Converts an array of scope strings to a single scope string per the OAuth 2 spec.
|
||||
@param scopes An array of scope strings.
|
||||
@return A space-delimited string of scopes.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
+ (NSString *)scopesWithArray:(NSArray<NSString *> *)scopes;
|
||||
|
||||
/*! @brief Converts an OAuth 2 spec-compliant scope string to an array of scopes.
|
||||
@param scopes An OAuth 2 spec-compliant scope string.
|
||||
@return An array of scope strings.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
+ (NSArray<NSString *> *)scopesArrayWithString:(NSString *)scopes;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
58
Pods/AppAuth/Source/AppAuthCore/OIDScopeUtilities.m
generated
Normal file
58
Pods/AppAuth/Source/AppAuthCore/OIDScopeUtilities.m
generated
Normal file
@ -0,0 +1,58 @@
|
||||
/*! @file OIDScopeUtilities.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDScopeUtilities.h"
|
||||
|
||||
@implementation OIDScopeUtilities
|
||||
|
||||
/*! @brief A character set with the characters NOT allowed in a scope name.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
+ (NSCharacterSet *)disallowedScopeCharacters {
|
||||
static NSCharacterSet *disallowedCharacters;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSMutableCharacterSet *allowedCharacters;
|
||||
allowedCharacters =
|
||||
[NSMutableCharacterSet characterSetWithRange:NSMakeRange(0x23, 0x5B - 0x23 + 1)];
|
||||
[allowedCharacters addCharactersInRange:NSMakeRange(0x5D, 0x7E - 0x5D + 1)];
|
||||
[allowedCharacters addCharactersInString:@"\x21"];
|
||||
disallowedCharacters = [allowedCharacters invertedSet];
|
||||
});
|
||||
return disallowedCharacters;
|
||||
}
|
||||
|
||||
+ (NSString *)scopesWithArray:(NSArray<NSString *> *)scopes {
|
||||
#if !defined(NS_BLOCK_ASSERTIONS)
|
||||
NSCharacterSet *disallowedCharacters = [self disallowedScopeCharacters];
|
||||
for (NSString *scope in scopes) {
|
||||
NSAssert(scope.length, @"Found illegal empty scope string.");
|
||||
NSAssert([scope rangeOfCharacterFromSet:disallowedCharacters].location == NSNotFound,
|
||||
@"Found illegal character in scope string.");
|
||||
}
|
||||
#endif // !defined(NS_BLOCK_ASSERTIONS)
|
||||
|
||||
NSString *scopeString = [scopes componentsJoinedByString:@" "];
|
||||
return scopeString;
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)scopesArrayWithString:(NSString *)scopes {
|
||||
return [scopes componentsSeparatedByString:@" "];
|
||||
}
|
||||
|
||||
@end
|
||||
46
Pods/AppAuth/Source/AppAuthCore/OIDScopes.h
generated
Normal file
46
Pods/AppAuth/Source/AppAuthCore/OIDScopes.h
generated
Normal file
@ -0,0 +1,46 @@
|
||||
/*! @file OIDScopes.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
/*! @brief Scope that indicates this request is an OpenID Connect request.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation
|
||||
*/
|
||||
extern NSString *const OIDScopeOpenID;
|
||||
|
||||
/*! @brief This scope value requests access to the End-User's default profile Claims, which are:
|
||||
name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture,
|
||||
website, gender, birthdate, zoneinfo, locale, and updated_at.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||
*/
|
||||
extern NSString *const OIDScopeProfile;
|
||||
|
||||
/*! @brief This scope value requests access to the email and email_verified Claims.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||
*/
|
||||
extern NSString *const OIDScopeEmail;
|
||||
|
||||
/*! @brief This scope value requests access to the address Claim.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||
*/
|
||||
extern NSString *const OIDScopeAddress;
|
||||
|
||||
/*! @brief This scope value requests access to the phone_number and phone_number_verified Claims.
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||
*/
|
||||
extern NSString *const OIDScopePhone;
|
||||
29
Pods/AppAuth/Source/AppAuthCore/OIDScopes.m
generated
Normal file
29
Pods/AppAuth/Source/AppAuthCore/OIDScopes.m
generated
Normal file
@ -0,0 +1,29 @@
|
||||
/*! @file OIDScopes.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDScopes.h"
|
||||
|
||||
NSString *const OIDScopeOpenID = @"openid";
|
||||
|
||||
NSString *const OIDScopeProfile = @"profile";
|
||||
|
||||
NSString *const OIDScopeEmail = @"email";
|
||||
|
||||
NSString *const OIDScopeAddress = @"address";
|
||||
|
||||
NSString *const OIDScopePhone = @"phone";
|
||||
118
Pods/AppAuth/Source/AppAuthCore/OIDServiceConfiguration.h
generated
Normal file
118
Pods/AppAuth/Source/AppAuthCore/OIDServiceConfiguration.h
generated
Normal file
@ -0,0 +1,118 @@
|
||||
/*! @file OIDServiceConfiguration.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDServiceConfiguration;
|
||||
@class OIDServiceDiscovery;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief The type of block called when a @c OIDServiceConfiguration has been created
|
||||
by loading a @c OIDServiceDiscovery from an @c NSURL.
|
||||
*/
|
||||
typedef void (^OIDServiceConfigurationCreated)
|
||||
(OIDServiceConfiguration *_Nullable serviceConfiguration,
|
||||
NSError *_Nullable error);
|
||||
|
||||
/*! @brief Represents the information needed to construct a @c OIDAuthorizationService.
|
||||
*/
|
||||
@interface OIDServiceConfiguration : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The authorization endpoint URI.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *authorizationEndpoint;
|
||||
|
||||
/*! @brief The token exchange and refresh endpoint URI.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *tokenEndpoint;
|
||||
|
||||
/*! @brief The OpenID Connect issuer.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *issuer;
|
||||
|
||||
/*! @brief The dynamic client registration endpoint URI.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *registrationEndpoint;
|
||||
|
||||
/*! @brief The end session logout endpoint URI.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *endSessionEndpoint;
|
||||
|
||||
/*! @brief The discovery document.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) OIDServiceDiscovery *discoveryDocument;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithAuthorizationEndpoint:tokenEndpoint: or
|
||||
@c initWithDiscoveryDocument:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @param authorizationEndpoint The authorization endpoint URI.
|
||||
@param tokenEndpoint The token exchange and refresh endpoint URI.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint;
|
||||
|
||||
/*! @param authorizationEndpoint The authorization endpoint URI.
|
||||
@param tokenEndpoint The token exchange and refresh endpoint URI.
|
||||
@param registrationEndpoint The dynamic client registration endpoint URI.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint;
|
||||
|
||||
/*! @param authorizationEndpoint The authorization endpoint URI.
|
||||
@param tokenEndpoint The token exchange and refresh endpoint URI.
|
||||
@param issuer The OpenID Connect issuer.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer;
|
||||
|
||||
/*! @param authorizationEndpoint The authorization endpoint URI.
|
||||
@param tokenEndpoint The token exchange and refresh endpoint URI.
|
||||
@param issuer The OpenID Connect issuer.
|
||||
@param registrationEndpoint The dynamic client registration endpoint URI.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint;
|
||||
|
||||
/*! @param authorizationEndpoint The authorization endpoint URI.
|
||||
@param tokenEndpoint The token exchange and refresh endpoint URI.
|
||||
@param issuer The OpenID Connect issuer.
|
||||
@param registrationEndpoint The dynamic client registration endpoint URI.
|
||||
@param endSessionEndpoint The end session endpoint (logout) URI.
|
||||
*/
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint
|
||||
endSessionEndpoint:(nullable NSURL *)endSessionEndpoint;
|
||||
|
||||
/*! @param discoveryDocument The discovery document from which to extract the required OAuth
|
||||
configuration.
|
||||
*/
|
||||
- (instancetype)initWithDiscoveryDocument:(OIDServiceDiscovery *)discoveryDocument;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
232
Pods/AppAuth/Source/AppAuthCore/OIDServiceConfiguration.m
generated
Normal file
232
Pods/AppAuth/Source/AppAuthCore/OIDServiceConfiguration.m
generated
Normal file
@ -0,0 +1,232 @@
|
||||
/*! @file OIDServiceConfiguration.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDServiceConfiguration.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
#import "OIDServiceDiscovery.h"
|
||||
|
||||
/*! @brief The key for the @c authorizationEndpoint property.
|
||||
*/
|
||||
static NSString *const kAuthorizationEndpointKey = @"authorizationEndpoint";
|
||||
|
||||
/*! @brief The key for the @c tokenEndpoint property.
|
||||
*/
|
||||
static NSString *const kTokenEndpointKey = @"tokenEndpoint";
|
||||
|
||||
/*! @brief The key for the @c issuer property.
|
||||
*/
|
||||
static NSString *const kIssuerKey = @"issuer";
|
||||
|
||||
/*! @brief The key for the @c registrationEndpoint property.
|
||||
*/
|
||||
static NSString *const kRegistrationEndpointKey = @"registrationEndpoint";
|
||||
|
||||
/*! @brief The key for the @c endSessionEndpoint property.
|
||||
*/
|
||||
static NSString *const kEndSessionEndpointKey = @"endSessionEndpoint";
|
||||
|
||||
/*! @brief The key for the @c discoveryDocument property.
|
||||
*/
|
||||
static NSString *const kDiscoveryDocumentKey = @"discoveryDocument";
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OIDServiceConfiguration ()
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint
|
||||
endSessionEndpoint:(nullable NSURL *)endSessionEndpoint
|
||||
discoveryDocument:(nullable OIDServiceDiscovery *)discoveryDocument
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OIDServiceConfiguration
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(
|
||||
initWithAuthorizationEndpoint:
|
||||
tokenEndpoint:)
|
||||
)
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint
|
||||
endSessionEndpoint:(nullable NSURL *)endSessionEndpoint
|
||||
discoveryDocument:(nullable OIDServiceDiscovery *)discoveryDocument {
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_authorizationEndpoint = [authorizationEndpoint copy];
|
||||
_tokenEndpoint = [tokenEndpoint copy];
|
||||
_issuer = [issuer copy];
|
||||
_registrationEndpoint = [registrationEndpoint copy];
|
||||
_endSessionEndpoint = [endSessionEndpoint copy];
|
||||
_discoveryDocument = [discoveryDocument copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint {
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:nil
|
||||
registrationEndpoint:nil
|
||||
endSessionEndpoint:nil
|
||||
discoveryDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint {
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:nil
|
||||
registrationEndpoint:registrationEndpoint
|
||||
endSessionEndpoint:nil
|
||||
discoveryDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer {
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:issuer
|
||||
registrationEndpoint:nil
|
||||
endSessionEndpoint:nil
|
||||
discoveryDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint {
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:issuer
|
||||
registrationEndpoint:registrationEndpoint
|
||||
endSessionEndpoint:nil
|
||||
discoveryDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint
|
||||
tokenEndpoint:(NSURL *)tokenEndpoint
|
||||
issuer:(nullable NSURL *)issuer
|
||||
registrationEndpoint:(nullable NSURL *)registrationEndpoint
|
||||
endSessionEndpoint:(nullable NSURL *)endSessionEndpoint {
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:issuer
|
||||
registrationEndpoint:registrationEndpoint
|
||||
endSessionEndpoint:endSessionEndpoint
|
||||
discoveryDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDiscoveryDocument:(OIDServiceDiscovery *) discoveryDocument {
|
||||
return [self initWithAuthorizationEndpoint:discoveryDocument.authorizationEndpoint
|
||||
tokenEndpoint:discoveryDocument.tokenEndpoint
|
||||
issuer:discoveryDocument.issuer
|
||||
registrationEndpoint:discoveryDocument.registrationEndpoint
|
||||
endSessionEndpoint:discoveryDocument.endSessionEndpoint
|
||||
discoveryDocument:discoveryDocument];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
NSURL *authorizationEndpoint = [aDecoder decodeObjectOfClass:[NSURL class]
|
||||
forKey:kAuthorizationEndpointKey];
|
||||
NSURL *tokenEndpoint = [aDecoder decodeObjectOfClass:[NSURL class]
|
||||
forKey:kTokenEndpointKey];
|
||||
NSURL *issuer = [aDecoder decodeObjectOfClass:[NSURL class]
|
||||
forKey:kIssuerKey];
|
||||
NSURL *registrationEndpoint = [aDecoder decodeObjectOfClass:[NSURL class]
|
||||
forKey:kRegistrationEndpointKey];
|
||||
NSURL *endSessionEndpoint = [aDecoder decodeObjectOfClass:[NSURL class]
|
||||
forKey:kEndSessionEndpointKey];
|
||||
// We don't accept nil authorizationEndpoints or tokenEndpoints.
|
||||
if (!authorizationEndpoint || !tokenEndpoint) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSSet<Class> *allowedClasses = [NSSet setWithArray:@[[OIDServiceDiscovery class],
|
||||
// The following classes are required in
|
||||
// order to support secure decoding of the
|
||||
// old OIDServiceDiscovery encoding.
|
||||
[NSDictionary class],
|
||||
[NSArray class],
|
||||
[NSString class],
|
||||
[NSNumber class],
|
||||
[NSNull class]]];
|
||||
OIDServiceDiscovery *discoveryDocument = [aDecoder decodeObjectOfClasses:allowedClasses
|
||||
forKey:kDiscoveryDocumentKey];
|
||||
|
||||
return [self initWithAuthorizationEndpoint:authorizationEndpoint
|
||||
tokenEndpoint:tokenEndpoint
|
||||
issuer:issuer
|
||||
registrationEndpoint:registrationEndpoint
|
||||
endSessionEndpoint:endSessionEndpoint
|
||||
discoveryDocument:discoveryDocument];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_authorizationEndpoint forKey:kAuthorizationEndpointKey];
|
||||
[aCoder encodeObject:_tokenEndpoint forKey:kTokenEndpointKey];
|
||||
[aCoder encodeObject:_issuer forKey:kIssuerKey];
|
||||
[aCoder encodeObject:_registrationEndpoint forKey:kRegistrationEndpointKey];
|
||||
[aCoder encodeObject:_discoveryDocument forKey:kDiscoveryDocumentKey];
|
||||
[aCoder encodeObject:_endSessionEndpoint forKey:kEndSessionEndpointKey];
|
||||
}
|
||||
|
||||
#pragma mark - description
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:
|
||||
@"OIDServiceConfiguration authorizationEndpoint: %@, tokenEndpoint: %@, "
|
||||
"registrationEndpoint: %@, endSessionEndpoint: %@, discoveryDocument: [%@]",
|
||||
_authorizationEndpoint,
|
||||
_tokenEndpoint,
|
||||
_registrationEndpoint,
|
||||
_endSessionEndpoint,
|
||||
_discoveryDocument];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
364
Pods/AppAuth/Source/AppAuthCore/OIDServiceDiscovery.h
generated
Normal file
364
Pods/AppAuth/Source/AppAuthCore/OIDServiceDiscovery.h
generated
Normal file
@ -0,0 +1,364 @@
|
||||
/*! @file OIDServiceDiscovery.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 Represents an OpenID Connect 1.0 Discovery Document
|
||||
@see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
||||
*/
|
||||
@interface OIDServiceDiscovery : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The decoded OpenID Connect 1.0 Discovery Document as a dictionary.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDictionary<NSString *, id> *discoveryDictionary;
|
||||
|
||||
/*! @brief REQUIRED. URL using the @c https scheme with no query or fragment component that the OP
|
||||
asserts as its Issuer Identifier. If Issuer discovery is supported, this value MUST be
|
||||
identical to the issuer value returned by WebFinger. This also MUST be identical to the
|
||||
@c iss Claim value in ID Tokens issued from this Issuer.
|
||||
@remarks issuer
|
||||
@seealso https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *issuer;
|
||||
|
||||
/*! @brief REQUIRED. URL of the OP's OAuth 2.0 Authorization Endpoint.
|
||||
@remarks authorization_endpoint
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *authorizationEndpoint;
|
||||
|
||||
/*! @brief OPTIONAL. URL of the OP's OAuth 2.0 Device Authorization Endpoint.
|
||||
@remarks device_authorization_endpoint
|
||||
@seealso https://tools.ietf.org/html/rfc8628#section-4
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *deviceAuthorizationEndpoint;
|
||||
|
||||
/*! @brief URL of the OP's OAuth 2.0 Token Endpoint. This is REQUIRED unless only the Implicit Flow
|
||||
is used.
|
||||
@remarks token_endpoint
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *tokenEndpoint;
|
||||
|
||||
/*! @brief RECOMMENDED. URL of the OP's UserInfo Endpoint. This URL MUST use the https scheme and
|
||||
MAY contain port, path, and query parameter components.
|
||||
@remarks userinfo_endpoint
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *userinfoEndpoint;
|
||||
|
||||
/*! @brief REQUIRED. URL of the OP's JSON Web Key Set document. This contains the signing key(s) the
|
||||
RP uses to validate signatures from the OP. The JWK Set MAY also contain the Server's
|
||||
encryption key(s), which are used by RPs to encrypt requests to the Server. When both
|
||||
signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED
|
||||
for all keys in the referenced JWK Set to indicate each key's intended usage. Although some
|
||||
algorithms allow the same key to be used for both signatures and encryption, doing so is NOT
|
||||
RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509
|
||||
representations of keys provided. When used, the bare key values MUST still be present and
|
||||
MUST match those in the certificate.
|
||||
@remarks jwks_uri
|
||||
@seealso http://tools.ietf.org/html/rfc7517
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL *jwksURL;
|
||||
|
||||
/*! @brief RECOMMENDED. URL of the OP's Dynamic Client Registration Endpoint.
|
||||
@remarks registration_endpoint
|
||||
@seealso http://openid.net/specs/openid-connect-registration-1_0.html
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *registrationEndpoint;
|
||||
|
||||
/* @brief OPTIONAL. URL of the OP's RP-Initiated Logout endpoint.
|
||||
@remarks end_session_endpoint
|
||||
@seealso http://openid.net/specs/openid-connect-session-1_0.html#OPMetadata
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *endSessionEndpoint;
|
||||
|
||||
/*! @brief RECOMMENDED. JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that
|
||||
this server supports. The server MUST support the openid scope value. Servers MAY choose not
|
||||
to advertise some supported scope values even when this parameter is used, although those
|
||||
defined in [OpenID.Core] SHOULD be listed, if supported.
|
||||
@remarks scopes_supported
|
||||
@seealso http://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *scopesSupported;
|
||||
|
||||
/*! @brief REQUIRED. JSON array containing a list of the OAuth 2.0 @c response_type values that this
|
||||
OP supports. Dynamic OpenID Providers MUST support the @c code, @c id_token, and the token
|
||||
@c id_token Response Type values.
|
||||
@remarks response_types_supported
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray<NSString *> *responseTypesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the OAuth 2.0 @c response_mode values that this
|
||||
OP supports, as specified in OAuth 2.0 Multiple Response Type Encoding Practices. If
|
||||
omitted, the default for Dynamic OpenID Providers is @c ["query", "fragment"].
|
||||
@remarks response_modes_supported
|
||||
@seealso http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *responseModesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the OAuth 2.0 Grant Type values that this OP
|
||||
supports. Dynamic OpenID Providers MUST support the @c authorization_code and @c implicit
|
||||
Grant Type values and MAY support other Grant Types. If omitted, the default value is
|
||||
@c ["authorization_code", "implicit"].
|
||||
@remarks grant_types_supported
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *grantTypesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the Authentication Context Class References
|
||||
that this OP supports.
|
||||
@remarks acr_values_supported
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *acrValuesSupported;
|
||||
|
||||
/*! @brief REQUIRED. JSON array containing a list of the Subject Identifier types that this OP
|
||||
supports. Valid types include @c pairwise and @c public.
|
||||
@remarks subject_types_supported
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray<NSString *> *subjectTypesSupported;
|
||||
|
||||
/*! @brief REQUIRED. JSON array containing a list of the JWS signing algorithms (@c alg values)
|
||||
supported by the OP for the ID Token to encode the Claims in a JWT. The algorithm @c RS256
|
||||
MUST be included. The value @c none MAY be supported, but MUST NOT be used unless the
|
||||
Response Type used returns no ID Token from the Authorization Endpoint (such as when using
|
||||
the Authorization Code Flow).
|
||||
@remarks id_token_signing_alg_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray<NSString *> *IDTokenSigningAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (@c alg values)
|
||||
supported by the OP for the ID Token to encode the Claims in a JWT.
|
||||
@remarks id_token_encryption_alg_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *IDTokenEncryptionAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (@c enc values)
|
||||
supported by the OP for the ID Token to encode the Claims in a JWT.
|
||||
@remarks id_token_encryption_enc_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *IDTokenEncryptionEncodingValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWS signing algorithms (@c alg values)
|
||||
supported by the UserInfo Endpoint to encode the Claims in a JWT. The value none MAY be
|
||||
included.
|
||||
@remarks userinfo_signing_alg_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7515
|
||||
@seealso https://tools.ietf.org/html/rfc7518
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *userinfoSigningAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values)
|
||||
supported by the UserInfo Endpoint to encode the Claims in a JWT.
|
||||
@remarks userinfo_encryption_alg_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7516
|
||||
@seealso https://tools.ietf.org/html/rfc7518
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *userinfoEncryptionAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (@c enc values)
|
||||
supported by the UserInfo Endpoint to encode the Claims in a JWT.
|
||||
@remarks userinfo_encryption_enc_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *userinfoEncryptionEncodingValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWS signing algorithms (@c alg values)
|
||||
supported by the OP for Request Objects, which are described in Section 6.1 of OpenID
|
||||
Connect Core 1.0. These algorithms are used both when the Request Object is passed by value
|
||||
(using the request parameter) and when it is passed by reference (using the @c request_uri
|
||||
parameter). Servers SHOULD support @c none and @c RS256.
|
||||
@remarks request_object_signing_alg_values_supported
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *requestObjectSigningAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (@c alg values)
|
||||
supported by the OP for Request Objects. These algorithms are used both when the Request
|
||||
Object is passed by value and when it is passed by reference.
|
||||
@remarks request_object_encryption_alg_values_supported
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *requestObjectEncryptionAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWE encryption algorithms (@c enc values)
|
||||
supported by the OP for Request Objects. These algorithms are used both when the Request
|
||||
Object is passed by value and when it is passed by reference.
|
||||
@remarks request_object_encryption_enc_values_supported
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *requestObjectEncryptionEncodingValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of Client Authentication methods supported by this
|
||||
Token Endpoint. The options are @c client_secret_post, @c client_secret_basic,
|
||||
@c client_secret_jwt, and @c private_key_jwt, as described in Section 9 of OpenID Connect
|
||||
Core 1.0. Other authentication methods MAY be defined by extensions. If omitted, the default
|
||||
is @c client_secret_basic -- the HTTP Basic Authentication Scheme specified in Section 2.3.1
|
||||
of OAuth 2.0.
|
||||
@remarks token_endpoint_auth_methods_supported
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html
|
||||
@seealso http://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *tokenEndpointAuthMethodsSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the JWS signing algorithms (@c alg values)
|
||||
supported by the Token Endpoint for the signature on the JWT used to authenticate the Client
|
||||
at the Token Endpoint for the @c private_key_jwt and @c client_secret_jwt authentication
|
||||
methods. Servers SHOULD support @c RS256. The value @c none MUST NOT be used.
|
||||
@remarks token_endpoint_auth_signing_alg_values_supported
|
||||
@seealso https://tools.ietf.org/html/rfc7519
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSArray<NSString *> *tokenEndpointAuthSigningAlgorithmValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the @c display parameter values that the OpenID
|
||||
Provider supports. These values are described in Section 3.1.2.1 of OpenID Connect Core 1.0.
|
||||
@remarks display_values_supported
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *displayValuesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. JSON array containing a list of the Claim Types that the OpenID Provider
|
||||
supports. These Claim Types are described in Section 5.6 of OpenID Connect Core 1.0. Values
|
||||
defined by this specification are @c normal, @c aggregated, and @c distributed. If omitted,
|
||||
the implementation supports only @c normal Claims.
|
||||
@remarks claim_types_supported
|
||||
@seealso http://openid.net/specs/openid-connect-core-1_0.html
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *claimTypesSupported;
|
||||
|
||||
/*! @brief RECOMMENDED. JSON array containing a list of the Claim Names of the Claims that the
|
||||
OpenID Provider MAY be able to supply values for. Note that for privacy or other reasons,
|
||||
this might not be an exhaustive list.
|
||||
@remarks claims_supported
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *claimsSupported;
|
||||
|
||||
/*! @brief OPTIONAL. URL of a page containing human-readable information that developers might want
|
||||
or need to know when using the OpenID Provider. In particular, if the OpenID Provider does
|
||||
not support Dynamic Client Registration, then information on how to register Clients needs
|
||||
to be provided in this documentation.
|
||||
@remarks service_documentation
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *serviceDocumentation;
|
||||
|
||||
/*! @brief OPTIONAL. Languages and scripts supported for values in Claims being returned,
|
||||
represented as a JSON array of BCP47 language tag values. Not all languages and scripts are
|
||||
necessarily supported for all Claim values.
|
||||
@remarks claims_locales_supported
|
||||
@seealso http://tools.ietf.org/html/rfc5646
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *claimsLocalesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. Languages and scripts supported for the user interface, represented as a JSON
|
||||
array of BCP47 language tag values.
|
||||
@remarks ui_locales_supported
|
||||
@seealso http://tools.ietf.org/html/rfc5646
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSArray<NSString *> *UILocalesSupported;
|
||||
|
||||
/*! @brief OPTIONAL. Boolean value specifying whether the OP supports use of the claims parameter,
|
||||
with @c true indicating support. If omitted, the default value is @c false.
|
||||
@remarks claims_parameter_supported
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL claimsParameterSupported;
|
||||
|
||||
/*! @brief OPTIONAL. Boolean value specifying whether the OP supports use of the request parameter,
|
||||
with @c true indicating support. If omitted, the default value is @c false.
|
||||
@remarks request_parameter_supported
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL requestParameterSupported;
|
||||
|
||||
/*! @brief OPTIONAL. Boolean value specifying whether the OP supports use of the @c request_uri
|
||||
parameter, with true indicating support. If omitted, the default value is @c true.
|
||||
@remarks request_uri_parameter_supported
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL requestURIParameterSupported;
|
||||
|
||||
/*! @brief OPTIONAL. Boolean value specifying whether the OP requires any @c request_uri values used
|
||||
to be pre-registered using the @c request_uris registration parameter. Pre-registration is
|
||||
REQUIRED when the value is @c true. If omitted, the default value is @c false.
|
||||
@remarks require_request_uri_registration
|
||||
*/
|
||||
@property(nonatomic, readonly) BOOL requireRequestURIRegistration;
|
||||
|
||||
/*! @brief OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to
|
||||
read about the OP's requirements on how the Relying Party can use the data provided by the
|
||||
OP. The registration process SHOULD display this URL to the person registering the Client if
|
||||
it is given.
|
||||
@remarks op_policy_uri
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *OPPolicyURI;
|
||||
|
||||
/*! @brief OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to
|
||||
read about OpenID Provider's terms of service. The registration process SHOULD display this
|
||||
URL to the person registering the Client if it is given.
|
||||
@remarks op_tos_uri
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *OPTosURI;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use @c initWithDictionary:error:, @c initWithJSON:error, or the
|
||||
@c discoverServiceConfigurationForDiscoveryURL:callback: from @c OIDAuthorizationService.
|
||||
*/
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Decodes a OpenID Connect Discovery 1.0 JSON document.
|
||||
@param serviceDiscoveryJSON An OpenID Connect Service Discovery document.
|
||||
@param error If a required field is missing from the dictionary, an error with domain
|
||||
@c ::OIDGeneralErrorDomain and code @c ::OIDErrorCodeInvalidDiscoveryDocument will be
|
||||
returned.
|
||||
*/
|
||||
- (nullable instancetype)initWithJSON:(NSString *)serviceDiscoveryJSON
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/*! @brief Decodes a OpenID Connect Discovery 1.0 JSON document.
|
||||
@param serviceDiscoveryJSONData An OpenID Connect Service Discovery document.
|
||||
@param error If a required field is missing from the dictionary, an error with domain
|
||||
@c ::OIDGeneralErrorDomain and code @c ::OIDErrorCodeInvalidDiscoveryDocument will be
|
||||
returned.
|
||||
*/
|
||||
- (nullable instancetype)initWithJSONData:(NSData *)serviceDiscoveryJSONData
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/*! @brief Designated initializer. The dictionary keys should match the keys defined in the OpenID
|
||||
Connect Discovery 1.0 standard for OpenID Provider Metadata.
|
||||
@param serviceDiscoveryDictionary A dictionary representing an OpenID Connect Service Discovery
|
||||
document.
|
||||
@param error If a required field is missing from the dictionary, an error with domain
|
||||
@c ::OIDGeneralErrorDomain and code @c ::OIDErrorCodeInvalidDiscoveryDocument will be
|
||||
returned.
|
||||
*/
|
||||
- (nullable instancetype)initWithDictionary:(NSDictionary *)serviceDiscoveryDictionary
|
||||
error:(NSError **_Nullable)error NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
393
Pods/AppAuth/Source/AppAuthCore/OIDServiceDiscovery.m
generated
Normal file
393
Pods/AppAuth/Source/AppAuthCore/OIDServiceDiscovery.m
generated
Normal file
@ -0,0 +1,393 @@
|
||||
/*! @file OIDServiceDiscovery.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDServiceDiscovery.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDErrorUtilities.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief The key for the @c discoveryDictionary property.
|
||||
*/
|
||||
static NSString *const kDiscoveryDictionaryKey = @"discoveryDictionary";
|
||||
|
||||
/*! Field keys associated with an OpenID Connect Discovery Document. */
|
||||
static NSString *const kIssuerKey = @"issuer";
|
||||
static NSString *const kAuthorizationEndpointKey = @"authorization_endpoint";
|
||||
static NSString *const kDeviceAuthorizationEndpointKey = @"device_authorization_endpoint";
|
||||
static NSString *const kTokenEndpointKey = @"token_endpoint";
|
||||
static NSString *const kUserinfoEndpointKey = @"userinfo_endpoint";
|
||||
static NSString *const kJWKSURLKey = @"jwks_uri";
|
||||
static NSString *const kRegistrationEndpointKey = @"registration_endpoint";
|
||||
static NSString *const kEndSessionEndpointKey = @"end_session_endpoint";
|
||||
static NSString *const kScopesSupportedKey = @"scopes_supported";
|
||||
static NSString *const kResponseTypesSupportedKey = @"response_types_supported";
|
||||
static NSString *const kResponseModesSupportedKey = @"response_modes_supported";
|
||||
static NSString *const kGrantTypesSupportedKey = @"grant_types_supported";
|
||||
static NSString *const kACRValuesSupportedKey = @"acr_values_supported";
|
||||
static NSString *const kSubjectTypesSupportedKey = @"subject_types_supported";
|
||||
static NSString *const kIDTokenSigningAlgorithmValuesSupportedKey =
|
||||
@"id_token_signing_alg_values_supported";
|
||||
static NSString *const kIDTokenEncryptionAlgorithmValuesSupportedKey =
|
||||
@"id_token_encryption_alg_values_supported";
|
||||
static NSString *const kIDTokenEncryptionEncodingValuesSupportedKey =
|
||||
@"id_token_encryption_enc_values_supported";
|
||||
static NSString *const kUserinfoSigningAlgorithmValuesSupportedKey =
|
||||
@"userinfo_signing_alg_values_supported";
|
||||
static NSString *const kUserinfoEncryptionAlgorithmValuesSupportedKey =
|
||||
@"userinfo_encryption_alg_values_supported";
|
||||
static NSString *const kUserinfoEncryptionEncodingValuesSupportedKey =
|
||||
@"userinfo_encryption_enc_values_supported";
|
||||
static NSString *const kRequestObjectSigningAlgorithmValuesSupportedKey =
|
||||
@"request_object_signing_alg_values_supported";
|
||||
static NSString *const kRequestObjectEncryptionAlgorithmValuesSupportedKey =
|
||||
@"request_object_encryption_alg_values_supported";
|
||||
static NSString *const kRequestObjectEncryptionEncodingValuesSupported =
|
||||
@"request_object_encryption_enc_values_supported";
|
||||
static NSString *const kTokenEndpointAuthMethodsSupportedKey =
|
||||
@"token_endpoint_auth_methods_supported";
|
||||
static NSString *const kTokenEndpointAuthSigningAlgorithmValuesSupportedKey =
|
||||
@"token_endpoint_auth_signing_alg_values_supported";
|
||||
static NSString *const kDisplayValuesSupportedKey = @"display_values_supported";
|
||||
static NSString *const kClaimTypesSupportedKey = @"claim_types_supported";
|
||||
static NSString *const kClaimsSupportedKey = @"claims_supported";
|
||||
static NSString *const kServiceDocumentationKey = @"service_documentation";
|
||||
static NSString *const kClaimsLocalesSupportedKey = @"claims_locales_supported";
|
||||
static NSString *const kUILocalesSupportedKey = @"ui_locales_supported";
|
||||
static NSString *const kClaimsParameterSupportedKey = @"claims_parameter_supported";
|
||||
static NSString *const kRequestParameterSupportedKey = @"request_parameter_supported";
|
||||
static NSString *const kRequestURIParameterSupportedKey = @"request_uri_parameter_supported";
|
||||
static NSString *const kRequireRequestURIRegistrationKey = @"require_request_uri_registration";
|
||||
static NSString *const kOPPolicyURIKey = @"op_policy_uri";
|
||||
static NSString *const kOPTosURIKey = @"op_tos_uri";
|
||||
|
||||
@implementation OIDServiceDiscovery {
|
||||
NSDictionary *_discoveryDictionary;
|
||||
}
|
||||
|
||||
- (nonnull instancetype)init OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithDictionary:error:))
|
||||
|
||||
- (nullable instancetype)initWithJSON:(NSString *)serviceDiscoveryJSON error:(NSError **)error {
|
||||
NSData *jsonData = [serviceDiscoveryJSON dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [self initWithJSONData:jsonData error:error];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithJSONData:(NSData *)serviceDiscoveryJSONData
|
||||
error:(NSError **_Nullable)error {
|
||||
NSError *jsonError;
|
||||
NSDictionary *json =
|
||||
[NSJSONSerialization JSONObjectWithData:serviceDiscoveryJSONData options:0 error:&jsonError];
|
||||
if (!json || jsonError) {
|
||||
*error = [OIDErrorUtilities errorWithCode:OIDErrorCodeJSONDeserializationError
|
||||
underlyingError:jsonError
|
||||
description:jsonError.localizedDescription];
|
||||
return nil;
|
||||
}
|
||||
if (![json isKindOfClass:[NSDictionary class]]) {
|
||||
*error = [OIDErrorUtilities errorWithCode:OIDErrorCodeInvalidDiscoveryDocument
|
||||
underlyingError:nil
|
||||
description:@"Discovery document isn't a dictionary"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self initWithDictionary:json error:error];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithDictionary:(NSDictionary *)serviceDiscoveryDictionary
|
||||
error:(NSError **_Nullable)error {
|
||||
if (![[self class] dictionaryHasRequiredFields:serviceDiscoveryDictionary error:error]) {
|
||||
return nil;
|
||||
}
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_discoveryDictionary = [serviceDiscoveryDictionary copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*! @brief Checks to see if the specified dictionary contains the required fields.
|
||||
@discussion This test is not meant to provide semantic analysis of the document (eg. fields
|
||||
where the value @c none is not an allowed option would not cause this method to fail if
|
||||
their value was @c none.) We are just testing to make sure we can meet the nullability
|
||||
contract we promised in the header.
|
||||
*/
|
||||
+ (BOOL)dictionaryHasRequiredFields:(NSDictionary<NSString *, id> *)dictionary
|
||||
error:(NSError **_Nullable)error {
|
||||
static NSString *const kMissingFieldErrorText = @"Missing field: %@";
|
||||
static NSString *const kInvalidURLFieldErrorText = @"Invalid URL: %@";
|
||||
|
||||
NSArray *requiredFields = @[
|
||||
kIssuerKey,
|
||||
kAuthorizationEndpointKey,
|
||||
kTokenEndpointKey,
|
||||
kJWKSURLKey,
|
||||
kResponseTypesSupportedKey,
|
||||
kSubjectTypesSupportedKey,
|
||||
kIDTokenSigningAlgorithmValuesSupportedKey
|
||||
];
|
||||
|
||||
for (NSString *field in requiredFields) {
|
||||
if (!dictionary[field]) {
|
||||
if (error) {
|
||||
NSString *errorText = [NSString stringWithFormat:kMissingFieldErrorText, field];
|
||||
*error = [OIDErrorUtilities errorWithCode:OIDErrorCodeInvalidDiscoveryDocument
|
||||
underlyingError:nil
|
||||
description:errorText];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Check required URL fields are valid URLs.
|
||||
NSArray *requiredURLFields = @[
|
||||
kIssuerKey,
|
||||
kTokenEndpointKey,
|
||||
kJWKSURLKey
|
||||
];
|
||||
|
||||
for (NSString *field in requiredURLFields) {
|
||||
if (![NSURL URLWithString:dictionary[field]]) {
|
||||
if (error) {
|
||||
NSString *errorText = [NSString stringWithFormat:kInvalidURLFieldErrorText, field];
|
||||
*error = [OIDErrorUtilities errorWithCode:OIDErrorCodeInvalidDiscoveryDocument
|
||||
underlyingError:nil
|
||||
description:errorText];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
NSError *error;
|
||||
NSDictionary *dictionary;
|
||||
if ([aDecoder containsValueForKey:kDiscoveryDictionaryKey]) {
|
||||
// We're decoding a collection type (NSDictionary) from NSJSONSerialization's
|
||||
// +JSONObjectWithData, so we need to include all classes that could potentially be contained
|
||||
// within.
|
||||
NSSet<Class> *allowedClasses = [NSSet setWithArray:@[[NSDictionary class],
|
||||
[NSArray class],
|
||||
[NSString class],
|
||||
[NSNumber class],
|
||||
[NSNull class]]];
|
||||
dictionary = [aDecoder decodeObjectOfClasses:allowedClasses
|
||||
forKey:kDiscoveryDictionaryKey];
|
||||
} else {
|
||||
// Decode using the old encoding which delegated to NSDictionary's encodeWithCoder:
|
||||
// implementation:
|
||||
//
|
||||
// - (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
// [_discoveryDictionary encodeWithCoder:aCoder];
|
||||
// }
|
||||
dictionary = [[NSDictionary alloc] initWithCoder:aDecoder];
|
||||
}
|
||||
self = [self initWithDictionary:dictionary error:&error];
|
||||
if (error) {
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_discoveryDictionary forKey:kDiscoveryDictionaryKey];
|
||||
// Provide forward compatibilty by continuing to add the old encoding.
|
||||
[_discoveryDictionary encodeWithCoder:aCoder];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (NSDictionary<NSString *, NSString *> *)discoveryDictionary {
|
||||
return _discoveryDictionary;
|
||||
}
|
||||
|
||||
- (NSURL *)issuer {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kIssuerKey]];
|
||||
}
|
||||
|
||||
- (NSURL *)authorizationEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kAuthorizationEndpointKey]];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)deviceAuthorizationEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kDeviceAuthorizationEndpointKey]];
|
||||
}
|
||||
|
||||
- (NSURL *)tokenEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kTokenEndpointKey]];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)userinfoEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kUserinfoEndpointKey]];
|
||||
}
|
||||
|
||||
- (NSURL *)jwksURL {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kJWKSURLKey]];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)registrationEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kRegistrationEndpointKey]];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)endSessionEndpoint {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kEndSessionEndpointKey]];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)scopesSupported {
|
||||
return _discoveryDictionary[kScopesSupportedKey];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)responseTypesSupported {
|
||||
return _discoveryDictionary[kResponseTypesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)responseModesSupported {
|
||||
return _discoveryDictionary[kResponseModesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)grantTypesSupported {
|
||||
return _discoveryDictionary[kGrantTypesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)acrValuesSupported {
|
||||
return _discoveryDictionary[kACRValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)subjectTypesSupported {
|
||||
return _discoveryDictionary[kSubjectTypesSupportedKey];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *) IDTokenSigningAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kIDTokenSigningAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)IDTokenEncryptionAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kIDTokenEncryptionAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)IDTokenEncryptionEncodingValuesSupported {
|
||||
return _discoveryDictionary[kIDTokenEncryptionEncodingValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)userinfoSigningAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kUserinfoSigningAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)userinfoEncryptionAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kUserinfoEncryptionAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)userinfoEncryptionEncodingValuesSupported {
|
||||
return _discoveryDictionary[kUserinfoEncryptionEncodingValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)requestObjectSigningAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kRequestObjectSigningAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *) requestObjectEncryptionAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kRequestObjectEncryptionAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *) requestObjectEncryptionEncodingValuesSupported {
|
||||
return _discoveryDictionary[kRequestObjectEncryptionEncodingValuesSupported];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)tokenEndpointAuthMethodsSupported {
|
||||
return _discoveryDictionary[kTokenEndpointAuthMethodsSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)tokenEndpointAuthSigningAlgorithmValuesSupported {
|
||||
return _discoveryDictionary[kTokenEndpointAuthSigningAlgorithmValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)displayValuesSupported {
|
||||
return _discoveryDictionary[kDisplayValuesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)claimTypesSupported {
|
||||
return _discoveryDictionary[kClaimTypesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)claimsSupported {
|
||||
return _discoveryDictionary[kClaimsSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)serviceDocumentation {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kServiceDocumentationKey]];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)claimsLocalesSupported {
|
||||
return _discoveryDictionary[kClaimsLocalesSupportedKey];
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)UILocalesSupported {
|
||||
return _discoveryDictionary[kUILocalesSupportedKey];
|
||||
}
|
||||
|
||||
- (BOOL)claimsParameterSupported {
|
||||
return [_discoveryDictionary[kClaimsParameterSupportedKey] boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)requestParameterSupported {
|
||||
return [_discoveryDictionary[kRequestParameterSupportedKey] boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)requestURIParameterSupported {
|
||||
// Default is true/YES.
|
||||
if (!_discoveryDictionary[kRequestURIParameterSupportedKey]) {
|
||||
return YES;
|
||||
}
|
||||
return [_discoveryDictionary[kRequestURIParameterSupportedKey] boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)requireRequestURIRegistration {
|
||||
return [_discoveryDictionary[kRequireRequestURIRegistrationKey] boolValue];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)OPPolicyURI {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kOPPolicyURIKey]];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)OPTosURI {
|
||||
return [NSURL URLWithString:_discoveryDictionary[kOPTosURIKey]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
167
Pods/AppAuth/Source/AppAuthCore/OIDTokenRequest.h
generated
Normal file
167
Pods/AppAuth/Source/AppAuthCore/OIDTokenRequest.h
generated
Normal file
@ -0,0 +1,167 @@
|
||||
/*! @file OIDTokenRequest.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
// This file only declares string constants useful for constructing a @c OIDTokenRequest, so it is
|
||||
// imported here for convenience.
|
||||
#import "OIDGrantTypes.h"
|
||||
|
||||
@class OIDAuthorizationResponse;
|
||||
@class OIDServiceConfiguration;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents a token request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.2
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
@interface OIDTokenRequest : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The service's configuration.
|
||||
@remarks This configuration specifies how to connect to a particular OAuth provider.
|
||||
Configurations may be created manually, or via an OpenID Connect Discovery Document.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDServiceConfiguration *configuration;
|
||||
|
||||
/*! @brief The type of token being sent to the token endpoint, i.e. "authorization_code" for the
|
||||
authorization code exchange, or "refresh_token" for an access token refresh request.
|
||||
@remarks grant_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
@see https://www.google.com/url?sa=D&q=https%3A%2F%2Ftools.ietf.org%2Fhtml%2Frfc6749%23section-6
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *grantType;
|
||||
|
||||
/*! @brief The authorization code received from the authorization server.
|
||||
@remarks code
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *authorizationCode;
|
||||
|
||||
/*! @brief The client's redirect URI.
|
||||
@remarks redirect_uri
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSURL *redirectURL;
|
||||
|
||||
/*! @brief The client identifier.
|
||||
@remarks client_id
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *clientID;
|
||||
|
||||
/*! @brief The client secret.
|
||||
@remarks client_secret
|
||||
@see https://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *clientSecret;
|
||||
|
||||
/*! @brief The value of the scope parameter is expressed as a list of space-delimited,
|
||||
case-sensitive strings.
|
||||
@remarks scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *scope;
|
||||
|
||||
/*! @brief The refresh token, which can be used to obtain new access tokens using the same
|
||||
authorization grant.
|
||||
@remarks refresh_token
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *refreshToken;
|
||||
|
||||
/*! @brief The PKCE code verifier used to redeem the authorization code.
|
||||
@remarks code_verifier
|
||||
@see https://tools.ietf.org/html/rfc7636#section-4.3
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *codeVerifier;
|
||||
|
||||
/*! @brief The client's additional token request parameters.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use
|
||||
initWithConfiguration:grantType:code:redirectURL:clientID:additionalParameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @param configuration The service's configuration.
|
||||
@param grantType the type of token being sent to the token endpoint, i.e. "authorization_code"
|
||||
for the authorization code exchange, or "refresh_token" for an access token refresh request.
|
||||
@see OIDGrantTypes.h
|
||||
@param code The authorization code received from the authorization server.
|
||||
@param redirectURL The client's redirect URI.
|
||||
@param clientID The client identifier.
|
||||
@param clientSecret The client secret.
|
||||
@param scopes An array of scopes to combine into a single scope string per the OAuth2 spec.
|
||||
@param refreshToken The refresh token.
|
||||
@param codeVerifier The PKCE code verifier.
|
||||
@param additionalParameters The client's additional token request parameters.
|
||||
*/
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
grantType:(NSString *)grantType
|
||||
authorizationCode:(nullable NSString *)code
|
||||
redirectURL:(nullable NSURL *)redirectURL
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
refreshToken:(nullable NSString *)refreshToken
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param configuration The service's configuration.
|
||||
@param grantType the type of token being sent to the token endpoint, i.e. "authorization_code"
|
||||
for the authorization code exchange, or "refresh_token" for an access token refresh request.
|
||||
@see OIDGrantTypes.h
|
||||
@param code The authorization code received from the authorization server.
|
||||
@param redirectURL The client's redirect URI.
|
||||
@param clientID The client identifier.
|
||||
@param clientSecret The client secret.
|
||||
@param scope The value of the scope parameter is expressed as a list of space-delimited,
|
||||
case-sensitive strings.
|
||||
@param refreshToken The refresh token.
|
||||
@param codeVerifier The PKCE code verifier.
|
||||
@param additionalParameters The client's additional token request parameters.
|
||||
*/
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
grantType:(NSString *)grantType
|
||||
authorizationCode:(nullable NSString *)code
|
||||
redirectURL:(nullable NSURL *)redirectURL
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scope:(nullable NSString *)scope
|
||||
refreshToken:(nullable NSString *)refreshToken
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Designated initializer for NSSecureCoding.
|
||||
@param aDecoder Unarchiver object to decode
|
||||
*/
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*! @brief Constructs an @c NSURLRequest representing the token request.
|
||||
@return An @c NSURLRequest representing the token request.
|
||||
*/
|
||||
- (NSURLRequest *)URLRequest;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
312
Pods/AppAuth/Source/AppAuthCore/OIDTokenRequest.m
generated
Normal file
312
Pods/AppAuth/Source/AppAuthCore/OIDTokenRequest.m
generated
Normal file
@ -0,0 +1,312 @@
|
||||
/*! @file OIDTokenRequest.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDTokenRequest.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDError.h"
|
||||
#import "OIDScopeUtilities.h"
|
||||
#import "OIDServiceConfiguration.h"
|
||||
#import "OIDURLQueryComponent.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
|
||||
/*! @brief The key for the @c configuration property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kConfigurationKey = @"configuration";
|
||||
|
||||
/*! @brief Key used to encode the @c grantType property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kGrantTypeKey = @"grant_type";
|
||||
|
||||
/*! @brief The key for the @c authorizationCode property for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kAuthorizationCodeKey = @"code";
|
||||
|
||||
/*! @brief Key used to encode the @c clientID property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kClientIDKey = @"client_id";
|
||||
|
||||
/*! @brief Key used to encode the @c clientSecret property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kClientSecretKey = @"client_secret";
|
||||
|
||||
/*! @brief Key used to encode the @c redirectURL property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRedirectURLKey = @"redirect_uri";
|
||||
|
||||
/*! @brief Key used to encode the @c scopes property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kScopeKey = @"scope";
|
||||
|
||||
/*! @brief Key used to encode the @c refreshToken property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRefreshTokenKey = @"refresh_token";
|
||||
|
||||
/*! @brief Key used to encode the @c codeVerifier property for @c NSSecureCoding and to build the
|
||||
request URL.
|
||||
*/
|
||||
static NSString *const kCodeVerifierKey = @"code_verifier";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for
|
||||
@c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
@implementation OIDTokenRequest
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(
|
||||
@selector(initWithConfiguration:
|
||||
grantType:
|
||||
authorizationCode:
|
||||
redirectURL:
|
||||
clientID:
|
||||
clientSecret:
|
||||
scope:
|
||||
refreshToken:
|
||||
codeVerifier:
|
||||
additionalParameters:)
|
||||
)
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
grantType:(NSString *)grantType
|
||||
authorizationCode:(nullable NSString *)code
|
||||
redirectURL:(nullable NSURL *)redirectURL
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scopes:(nullable NSArray<NSString *> *)scopes
|
||||
refreshToken:(nullable NSString *)refreshToken
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
return [self initWithConfiguration:configuration
|
||||
grantType:grantType
|
||||
authorizationCode:code
|
||||
redirectURL:redirectURL
|
||||
clientID:clientID
|
||||
clientSecret:clientSecret
|
||||
scope:[OIDScopeUtilities scopesWithArray:scopes]
|
||||
refreshToken:refreshToken
|
||||
codeVerifier:(NSString *)codeVerifier
|
||||
additionalParameters:additionalParameters];
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(OIDServiceConfiguration *)configuration
|
||||
grantType:(NSString *)grantType
|
||||
authorizationCode:(nullable NSString *)code
|
||||
redirectURL:(nullable NSURL *)redirectURL
|
||||
clientID:(NSString *)clientID
|
||||
clientSecret:(nullable NSString *)clientSecret
|
||||
scope:(nullable NSString *)scope
|
||||
refreshToken:(nullable NSString *)refreshToken
|
||||
codeVerifier:(nullable NSString *)codeVerifier
|
||||
additionalParameters:(nullable NSDictionary<NSString *, NSString *> *)additionalParameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configuration = [configuration copy];
|
||||
_grantType = [grantType copy];
|
||||
_authorizationCode = [code copy];
|
||||
_redirectURL = [redirectURL copy];
|
||||
_clientID = [clientID copy];
|
||||
_clientSecret = [clientSecret copy];
|
||||
_scope = [scope copy];
|
||||
_refreshToken = [refreshToken copy];
|
||||
_codeVerifier = [codeVerifier copy];
|
||||
_additionalParameters =
|
||||
[[NSDictionary alloc] initWithDictionary:additionalParameters copyItems:YES];
|
||||
|
||||
// Additional validation for the authorization_code grant type
|
||||
if ([_grantType isEqual:OIDGrantTypeAuthorizationCode]) {
|
||||
// redirect URI must not be nil
|
||||
if (!_redirectURL) {
|
||||
[NSException raise:OIDOAuthExceptionInvalidTokenRequestNullRedirectURL
|
||||
format:@"%@", OIDOAuthExceptionInvalidTokenRequestNullRedirectURL, nil];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDServiceConfiguration *configuration =
|
||||
[aDecoder decodeObjectOfClass:[OIDServiceConfiguration class]
|
||||
forKey:kConfigurationKey];
|
||||
NSString *grantType = [aDecoder decodeObjectOfClass:[NSString class] forKey:kGrantTypeKey];
|
||||
NSString *code = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAuthorizationCodeKey];
|
||||
NSString *clientID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kClientIDKey];
|
||||
NSString *clientSecret = [aDecoder decodeObjectOfClass:[NSString class] forKey:kClientSecretKey];
|
||||
NSString *scope = [aDecoder decodeObjectOfClass:[NSString class] forKey:kScopeKey];
|
||||
NSString *refreshToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kRefreshTokenKey];
|
||||
NSString *codeVerifier = [aDecoder decodeObjectOfClass:[NSString class] forKey:kCodeVerifierKey];
|
||||
NSURL *redirectURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kRedirectURLKey];
|
||||
NSSet *additionalParameterCodingClasses = [NSSet setWithArray:@[
|
||||
[NSDictionary class],
|
||||
[NSString class]
|
||||
]];
|
||||
NSDictionary *additionalParameters =
|
||||
[aDecoder decodeObjectOfClasses:additionalParameterCodingClasses
|
||||
forKey:kAdditionalParametersKey];
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_configuration = [configuration copy];
|
||||
_grantType = [grantType copy];
|
||||
_authorizationCode = [code copy];
|
||||
_redirectURL = [redirectURL copy];
|
||||
_clientID = [clientID copy];
|
||||
_clientSecret = [clientSecret copy];
|
||||
_scope = [scope copy];
|
||||
_refreshToken = [refreshToken copy];
|
||||
_codeVerifier = [codeVerifier copy];
|
||||
_additionalParameters =
|
||||
[[NSDictionary alloc] initWithDictionary:additionalParameters copyItems:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_configuration forKey:kConfigurationKey];
|
||||
[aCoder encodeObject:_grantType forKey:kGrantTypeKey];
|
||||
[aCoder encodeObject:_authorizationCode forKey:kAuthorizationCodeKey];
|
||||
[aCoder encodeObject:_clientID forKey:kClientIDKey];
|
||||
[aCoder encodeObject:_clientSecret forKey:kClientSecretKey];
|
||||
[aCoder encodeObject:_redirectURL forKey:kRedirectURLKey];
|
||||
[aCoder encodeObject:_scope forKey:kScopeKey];
|
||||
[aCoder encodeObject:_refreshToken forKey:kRefreshTokenKey];
|
||||
[aCoder encodeObject:_codeVerifier forKey:kCodeVerifierKey];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
NSURLRequest *request = self.URLRequest;
|
||||
NSString *requestBody =
|
||||
[[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
|
||||
return [NSString stringWithFormat:@"<%@: %p, request: <URL: %@, HTTPBody: %@>>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
request.URL,
|
||||
requestBody];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*! @brief Constructs the request URI.
|
||||
@return A URL representing the token request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
- (NSURL *)tokenRequestURL {
|
||||
return _configuration.tokenEndpoint;
|
||||
}
|
||||
|
||||
/*! @brief Constructs the request body data by combining the request parameters using the
|
||||
"application/x-www-form-urlencoded" format.
|
||||
@return The data to pass to the token request URL.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
- (OIDURLQueryComponent *)tokenRequestBody {
|
||||
OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] init];
|
||||
|
||||
// Add parameters, as applicable.
|
||||
if (_grantType) {
|
||||
[query addParameter:kGrantTypeKey value:_grantType];
|
||||
}
|
||||
if (_scope) {
|
||||
[query addParameter:kScopeKey value:_scope];
|
||||
}
|
||||
if (_redirectURL) {
|
||||
[query addParameter:kRedirectURLKey value:_redirectURL.absoluteString];
|
||||
}
|
||||
if (_refreshToken) {
|
||||
[query addParameter:kRefreshTokenKey value:_refreshToken];
|
||||
}
|
||||
if (_authorizationCode) {
|
||||
[query addParameter:kAuthorizationCodeKey value:_authorizationCode];
|
||||
}
|
||||
if (_codeVerifier) {
|
||||
[query addParameter:kCodeVerifierKey value:_codeVerifier];
|
||||
}
|
||||
|
||||
// Add any additional parameters the client has specified.
|
||||
[query addParameters:_additionalParameters];
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
- (NSURLRequest *)URLRequest {
|
||||
static NSString *const kHTTPPost = @"POST";
|
||||
static NSString *const kHTTPContentTypeHeaderKey = @"Content-Type";
|
||||
static NSString *const kHTTPContentTypeHeaderValue =
|
||||
@"application/x-www-form-urlencoded; charset=UTF-8";
|
||||
|
||||
NSURL *tokenRequestURL = [self tokenRequestURL];
|
||||
NSMutableURLRequest *URLRequest = [[NSURLRequest requestWithURL:tokenRequestURL] mutableCopy];
|
||||
URLRequest.HTTPMethod = kHTTPPost;
|
||||
[URLRequest setValue:kHTTPContentTypeHeaderValue forHTTPHeaderField:kHTTPContentTypeHeaderKey];
|
||||
|
||||
OIDURLQueryComponent *bodyParameters = [self tokenRequestBody];
|
||||
NSMutableDictionary *httpHeaders = [[NSMutableDictionary alloc] init];
|
||||
|
||||
if (_clientSecret) {
|
||||
// The client id and secret are encoded using the "application/x-www-form-urlencoded"
|
||||
// encoding algorithm per RFC 6749 Section 2.3.1.
|
||||
// https://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
NSString *encodedClientID = [OIDTokenUtilities formUrlEncode:_clientID];
|
||||
NSString *encodedClientSecret = [OIDTokenUtilities formUrlEncode:_clientSecret];
|
||||
|
||||
NSString *credentials =
|
||||
[NSString stringWithFormat:@"%@:%@", encodedClientID, encodedClientSecret];
|
||||
NSData *plainData = [credentials dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *basicAuth = [plainData base64EncodedStringWithOptions:kNilOptions];
|
||||
|
||||
NSString *authValue = [NSString stringWithFormat:@"Basic %@", basicAuth];
|
||||
[httpHeaders setObject:authValue forKey:@"Authorization"];
|
||||
} else {
|
||||
[bodyParameters addParameter:kClientIDKey value:_clientID];
|
||||
}
|
||||
|
||||
// Constructs request with the body string and headers.
|
||||
NSString *bodyString = [bodyParameters URLEncodedParameters];
|
||||
NSData *body = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
URLRequest.HTTPBody = body;
|
||||
|
||||
for (id header in httpHeaders) {
|
||||
[URLRequest setValue:httpHeaders[header] forHTTPHeaderField:header];
|
||||
}
|
||||
|
||||
return URLRequest;
|
||||
}
|
||||
|
||||
@end
|
||||
110
Pods/AppAuth/Source/AppAuthCore/OIDTokenResponse.h
generated
Normal file
110
Pods/AppAuth/Source/AppAuthCore/OIDTokenResponse.h
generated
Normal file
@ -0,0 +1,110 @@
|
||||
/*! @file OIDTokenResponse.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDTokenRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief Represents the response to an token request.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-3.2
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
@interface OIDTokenResponse : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
/*! @brief The request which was serviced.
|
||||
*/
|
||||
@property(nonatomic, readonly) OIDTokenRequest *request;
|
||||
|
||||
/*! @brief The access token generated by the authorization server.
|
||||
@remarks access_token
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *accessToken;
|
||||
|
||||
/*! @brief The approximate expiration date & time of the access token.
|
||||
@remarks expires_in
|
||||
@seealso OIDTokenResponse.accessToken
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSDate *accessTokenExpirationDate;
|
||||
|
||||
/*! @brief Typically "Bearer" when present. Otherwise, another token_type value that the Client has
|
||||
negotiated with the Authorization Server.
|
||||
@remarks token_type
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.4
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *tokenType;
|
||||
|
||||
/*! @brief ID Token value associated with the authenticated session. Always present for the
|
||||
authorization code grant exchange when OpenID Connect is used, optional for responses to
|
||||
access token refresh requests. Note that AppAuth does NOT verify the JWT signature. Users
|
||||
of AppAuth are encouraged to verifying the JWT signature using the validation library of
|
||||
their choosing.
|
||||
@remarks id_token
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse
|
||||
@see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
@see https://jwt.io
|
||||
@discussion @c OIDIDToken can be used to parse the ID Token and extract the claims. As noted,
|
||||
this class does not verify the JWT signature.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *idToken;
|
||||
|
||||
/*! @brief The refresh token, which can be used to obtain new access tokens using the same
|
||||
authorization grant
|
||||
@remarks refresh_token
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *refreshToken;
|
||||
|
||||
/*! @brief The scope of the access token. OPTIONAL, if identical to the scopes requested, otherwise,
|
||||
REQUIRED.
|
||||
@remarks scope
|
||||
@see https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *scope;
|
||||
|
||||
/*! @brief Additional parameters returned from the token server.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters;
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. Please use initWithParameters:.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Designated initializer.
|
||||
@param request The serviced request.
|
||||
@param parameters The decoded parameters returned from the Authorization Server.
|
||||
@remarks Known parameters are extracted from the @c parameters parameter and the normative
|
||||
properties are populated. Non-normative parameters are placed in the
|
||||
@c #additionalParameters dictionary.
|
||||
*/
|
||||
- (instancetype)initWithRequest:(OIDTokenRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
163
Pods/AppAuth/Source/AppAuthCore/OIDTokenResponse.m
generated
Normal file
163
Pods/AppAuth/Source/AppAuthCore/OIDTokenResponse.m
generated
Normal file
@ -0,0 +1,163 @@
|
||||
/*! @file OIDTokenResponse.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDTokenResponse.h"
|
||||
|
||||
#import "OIDDefines.h"
|
||||
#import "OIDFieldMapping.h"
|
||||
#import "OIDTokenRequest.h"
|
||||
#import "OIDTokenUtilities.h"
|
||||
|
||||
/*! @brief Key used to encode the @c request property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kRequestKey = @"request";
|
||||
|
||||
/*! @brief The key for the @c accessToken property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kAccessTokenKey = @"access_token";
|
||||
|
||||
/*! @brief The key for the @c accessTokenExpirationDate property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kExpiresInKey = @"expires_in";
|
||||
|
||||
/*! @brief The key for the @c tokenType property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kTokenTypeKey = @"token_type";
|
||||
|
||||
/*! @brief The key for the @c idToken property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kIDTokenKey = @"id_token";
|
||||
|
||||
/*! @brief The key for the @c refreshToken property in the incoming parameters and for
|
||||
@c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kRefreshTokenKey = @"refresh_token";
|
||||
|
||||
/*! @brief The key for the @c scope property in the incoming parameters and for @c NSSecureCoding.
|
||||
*/
|
||||
static NSString *const kScopeKey = @"scope";
|
||||
|
||||
/*! @brief Key used to encode the @c additionalParameters property for @c NSSecureCoding
|
||||
*/
|
||||
static NSString *const kAdditionalParametersKey = @"additionalParameters";
|
||||
|
||||
@implementation OIDTokenResponse
|
||||
|
||||
/*! @brief Returns a mapping of incoming parameters to instance variables.
|
||||
@return A mapping of incoming parameters to instance variables.
|
||||
*/
|
||||
+ (NSDictionary<NSString *, OIDFieldMapping *> *)fieldMap {
|
||||
static NSMutableDictionary<NSString *, OIDFieldMapping *> *fieldMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
fieldMap = [NSMutableDictionary dictionary];
|
||||
fieldMap[kAccessTokenKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_accessToken" type:[NSString class]];
|
||||
fieldMap[kExpiresInKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_accessTokenExpirationDate"
|
||||
type:[NSDate class]
|
||||
conversion:[OIDFieldMapping dateSinceNowConversion]];
|
||||
fieldMap[kTokenTypeKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_tokenType" type:[NSString class]];
|
||||
fieldMap[kIDTokenKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_idToken" type:[NSString class]];
|
||||
fieldMap[kRefreshTokenKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_refreshToken" type:[NSString class]];
|
||||
fieldMap[kScopeKey] =
|
||||
[[OIDFieldMapping alloc] initWithName:@"_scope" type:[NSString class]];
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
#pragma mark - Initializers
|
||||
|
||||
- (instancetype)init
|
||||
OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithRequest:parameters:))
|
||||
|
||||
- (instancetype)initWithRequest:(OIDTokenRequest *)request
|
||||
parameters:(NSDictionary<NSString *, NSObject<NSCopying> *> *)parameters {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_request = [request copy];
|
||||
NSDictionary<NSString *, NSObject<NSCopying> *> *additionalParameters =
|
||||
[OIDFieldMapping remainingParametersWithMap:[[self class] fieldMap]
|
||||
parameters:parameters
|
||||
instance:self];
|
||||
_additionalParameters = additionalParameters;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(nullable NSZone *)zone {
|
||||
// The documentation for NSCopying specifically advises us to return a reference to the original
|
||||
// instance in the case where instances are immutable (as ours is):
|
||||
// "Implement NSCopying by retaining the original instead of creating a new copy when the class
|
||||
// and its contents are immutable."
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
OIDTokenRequest *request =
|
||||
[aDecoder decodeObjectOfClass:[OIDTokenRequest class] forKey:kRequestKey];
|
||||
self = [self initWithRequest:request parameters:@{ }];
|
||||
if (self) {
|
||||
[OIDFieldMapping decodeWithCoder:aDecoder map:[[self class] fieldMap] instance:self];
|
||||
_additionalParameters = [aDecoder decodeObjectOfClasses:[OIDFieldMapping JSONTypes]
|
||||
forKey:kAdditionalParametersKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[OIDFieldMapping encodeWithCoder:aCoder map:[[self class] fieldMap] instance:self];
|
||||
[aCoder encodeObject:_request forKey:kRequestKey];
|
||||
[aCoder encodeObject:_additionalParameters forKey:kAdditionalParametersKey];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, accessToken: \"%@\", accessTokenExpirationDate: %@, "
|
||||
"tokenType: %@, idToken: \"%@\", refreshToken: \"%@\", "
|
||||
"scope: \"%@\", additionalParameters: %@, request: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
[OIDTokenUtilities redact:_accessToken],
|
||||
_accessTokenExpirationDate,
|
||||
_tokenType,
|
||||
[OIDTokenUtilities redact:_idToken],
|
||||
[OIDTokenUtilities redact:_refreshToken],
|
||||
_scope,
|
||||
_additionalParameters,
|
||||
_request];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@end
|
||||
67
Pods/AppAuth/Source/AppAuthCore/OIDTokenUtilities.h
generated
Normal file
67
Pods/AppAuth/Source/AppAuthCore/OIDTokenUtilities.h
generated
Normal file
@ -0,0 +1,67 @@
|
||||
/*! @file OIDTokenUtilities.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 Provides data encoding/decoding methods, random string generators, etc.
|
||||
*/
|
||||
@interface OIDTokenUtilities : NSObject
|
||||
|
||||
/*! @internal
|
||||
@brief Unavailable. This class should not be initialized.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/*! @brief Base64url-nopadding encodes the given data.
|
||||
@param data The input data.
|
||||
@return The base64url encoded data as a NSString.
|
||||
@discussion Base64url-nopadding is used in several identity specs such as PKCE and
|
||||
OpenID Connect.
|
||||
*/
|
||||
+ (NSString *)encodeBase64urlNoPadding:(NSData *)data;
|
||||
|
||||
/*! @brief Generates a URL-safe string of random data.
|
||||
@param size The number of random bytes to encode. NB. the length of the output string will be
|
||||
greater than the number of random bytes, due to the URL-safe encoding.
|
||||
@return Random data encoded with base64url.
|
||||
*/
|
||||
+ (nullable NSString *)randomURLSafeStringWithSize:(NSUInteger)size;
|
||||
|
||||
/*! @brief SHA256 hashes the input string.
|
||||
@param inputString The input string.
|
||||
@return The SHA256 data.
|
||||
*/
|
||||
+ (NSData *)sha256:(NSString *)inputString;
|
||||
|
||||
/*! @brief Truncated intput string after first 6 characters followed by ellipses
|
||||
@param inputString The input string.
|
||||
@return Truncated string.
|
||||
*/
|
||||
+ (nullable NSString *)redact:(nullable NSString *)inputString;
|
||||
|
||||
/*! @brief Form url encode the input string by applying application/x-www-form-urlencoded algorithm
|
||||
@param inputString The input string.
|
||||
@return The encoded string.
|
||||
*/
|
||||
+ (NSString*)formUrlEncode:(NSString*)inputString;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
89
Pods/AppAuth/Source/AppAuthCore/OIDTokenUtilities.m
generated
Normal file
89
Pods/AppAuth/Source/AppAuthCore/OIDTokenUtilities.m
generated
Normal file
@ -0,0 +1,89 @@
|
||||
/*! @file OIDTokenUtilities.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDTokenUtilities.h"
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
/*! @brief String representing the set of characters that are allowed as is for the
|
||||
application/x-www-form-urlencoded encoding algorithm.
|
||||
*/
|
||||
static NSString *const kFormUrlEncodedAllowedCharacters =
|
||||
@" *-._0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
@implementation OIDTokenUtilities
|
||||
|
||||
+ (NSString *)encodeBase64urlNoPadding:(NSData *)data {
|
||||
NSString *base64string = [data base64EncodedStringWithOptions:0];
|
||||
// converts base64 to base64url
|
||||
base64string = [base64string stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
|
||||
base64string = [base64string stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
||||
// strips padding
|
||||
base64string = [base64string stringByReplacingOccurrencesOfString:@"=" withString:@""];
|
||||
return base64string;
|
||||
}
|
||||
|
||||
+ (nullable NSString *)randomURLSafeStringWithSize:(NSUInteger)size {
|
||||
NSMutableData *randomData = [NSMutableData dataWithLength:size];
|
||||
int result = SecRandomCopyBytes(kSecRandomDefault, randomData.length, randomData.mutableBytes);
|
||||
if (result != 0) {
|
||||
return nil;
|
||||
}
|
||||
return [[self class] encodeBase64urlNoPadding:randomData];
|
||||
}
|
||||
|
||||
+ (NSData *)sha256:(NSString *)inputString {
|
||||
NSData *verifierData = [inputString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSMutableData *sha256Verifier = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(verifierData.bytes, (CC_LONG)verifierData.length, sha256Verifier.mutableBytes);
|
||||
return sha256Verifier;
|
||||
}
|
||||
|
||||
+ (NSString *)redact:(NSString *)inputString {
|
||||
if (inputString == nil) {
|
||||
return nil;
|
||||
}
|
||||
switch(inputString.length){
|
||||
case 0:
|
||||
return @"";
|
||||
case 1 ... 8:
|
||||
return @"[redacted]";
|
||||
case 9:
|
||||
default:
|
||||
return [[inputString substringToIndex:6] stringByAppendingString:@"...[redacted]"];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString*)formUrlEncode:(NSString*)inputString {
|
||||
// https://www.w3.org/TR/html5/sec-forms.html#application-x-www-form-urlencoded-encoding-algorithm
|
||||
// Following the spec from the above link, application/x-www-form-urlencoded percent encode all
|
||||
// the characters except *-._A-Za-z0-9
|
||||
// Space character is replaced by + in the resulting bytes sequence
|
||||
if (inputString.length == 0) {
|
||||
return inputString;
|
||||
}
|
||||
NSCharacterSet *allowedCharacters =
|
||||
[NSCharacterSet characterSetWithCharactersInString:kFormUrlEncodedAllowedCharacters];
|
||||
// Percent encode all characters not present in the provided set.
|
||||
NSString *encodedString =
|
||||
[inputString stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
|
||||
// Replace occurences of space by '+' character
|
||||
return [encodedString stringByReplacingOccurrencesOfString:@" " withString:@"+"];
|
||||
}
|
||||
|
||||
@end
|
||||
93
Pods/AppAuth/Source/AppAuthCore/OIDURLQueryComponent.h
generated
Normal file
93
Pods/AppAuth/Source/AppAuthCore/OIDURLQueryComponent.h
generated
Normal file
@ -0,0 +1,93 @@
|
||||
/*! @file OIDURLQueryComponent.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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>
|
||||
|
||||
@class OIDAuthorizationRequest;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*! @brief If set to YES, will force the iOS 7-only code for @c OIDURLQueryComponent to be used,
|
||||
even on non-iOS 7 devices and simulators. Useful for testing the iOS 7 code paths on the
|
||||
simulator. Defaults to NO.
|
||||
*/
|
||||
extern BOOL gOIDURLQueryComponentForceIOS7Handling;
|
||||
|
||||
/*! @brief A utility class for creating and parsing URL query components encoded with the
|
||||
application/x-www-form-urlencoded format.
|
||||
@description Supports application/x-www-form-urlencoded encoding and decoding, specifically
|
||||
'+' is replaced with space before percent decoding. For encoding, simply percent encodes
|
||||
space, as this is valid application/x-www-form-urlencoded.
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.2
|
||||
@see https://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
@see https://tools.ietf.org/html/rfc6749#appendix-B
|
||||
@see https://url.spec.whatwg.org/#urlencoded-parsing
|
||||
*/
|
||||
@interface OIDURLQueryComponent : NSObject
|
||||
|
||||
/*! @brief The parameter names in the query.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSArray<NSString *> *parameters;
|
||||
|
||||
/*! @brief The parameters represented as a dictionary.
|
||||
@remarks All values are @c NSString except for parameters which contain multiple values, in
|
||||
which case the value is an @c NSArray<NSString *> *.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSDictionary<NSString *, NSObject<NSCopying> *> *dictionaryValue;
|
||||
|
||||
/*! @brief Creates an @c OIDURLQueryComponent by parsing the query string in a URL.
|
||||
@param URL The URL from which to extract a query component.
|
||||
*/
|
||||
- (nullable instancetype)initWithURL:(NSURL *)URL;
|
||||
|
||||
/*! @brief The value (or values) for a named parameter in the query.
|
||||
@param parameter The parameter name. Case sensitive.
|
||||
@return The value (or values) for a named parameter in the query.
|
||||
*/
|
||||
- (NSArray<NSString *> *)valuesForParameter:(NSString *)parameter;
|
||||
|
||||
/*! @brief Adds a parameter value to the query.
|
||||
@param parameter The name of the parameter. Case sensitive.
|
||||
@param value The value to add.
|
||||
*/
|
||||
- (void)addParameter:(NSString *)parameter value:(NSString *)value;
|
||||
|
||||
/*! @brief Adds multiple parameters with associated values to the query.
|
||||
@param parameters The parameter name value pairs to add to the query.
|
||||
*/
|
||||
- (void)addParameters:(NSDictionary<NSString *, NSString *> *)parameters;
|
||||
|
||||
/*! @param URL The URL to add the query component to.
|
||||
@return The original URL with the query component replaced by the parameters from this query.
|
||||
*/
|
||||
- (NSURL *)URLByReplacingQueryInURL:(NSURL *)URL;
|
||||
|
||||
/*! @brief Builds an x-www-form-urlencoded string representing the parameters.
|
||||
@return The x-www-form-urlencoded string representing the parameters.
|
||||
*/
|
||||
- (NSString *)URLEncodedParameters;
|
||||
|
||||
/*! @brief A NSMutableCharacterSet containing allowed characters in URL parameter values (that is
|
||||
the "value" part of "?key=value"). This has less allowed characters than
|
||||
@c URLQueryAllowedCharacterSet, as the query component includes both the key & value.
|
||||
*/
|
||||
+ (NSMutableCharacterSet *)URLParamValueAllowedCharacters;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
219
Pods/AppAuth/Source/AppAuthCore/OIDURLQueryComponent.m
generated
Normal file
219
Pods/AppAuth/Source/AppAuthCore/OIDURLQueryComponent.m
generated
Normal file
@ -0,0 +1,219 @@
|
||||
/*! @file OIDURLQueryComponent.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDURLQueryComponent.h"
|
||||
|
||||
BOOL gOIDURLQueryComponentForceIOS7Handling = NO;
|
||||
|
||||
/*! @brief String representing the set of characters that are valid for the URL query
|
||||
(per @ NSCharacterSet.URLQueryAllowedCharacterSet), but are disallowed in URL query
|
||||
parameters and values.
|
||||
*/
|
||||
static NSString *const kQueryStringParamAdditionalDisallowedCharacters = @"=&+";
|
||||
|
||||
@implementation OIDURLQueryComponent {
|
||||
/*! @brief A dictionary of parameter names and values representing the contents of the query.
|
||||
*/
|
||||
NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> *_parameters;
|
||||
}
|
||||
|
||||
- (nullable instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_parameters = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithURL:(NSURL *)URL {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
if (@available(iOS 8.0, macOS 10.10, *)) {
|
||||
// If NSURLQueryItem is available, use it for deconstructing the new URL. (iOS 8+)
|
||||
if (!gOIDURLQueryComponentForceIOS7Handling) {
|
||||
NSURLComponents *components =
|
||||
[NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
|
||||
// As OAuth uses application/x-www-form-urlencoded encoding, interprets '+' as a space
|
||||
// in addition to regular percent decoding. https://url.spec.whatwg.org/#urlencoded-parsing
|
||||
components.percentEncodedQuery =
|
||||
[components.percentEncodedQuery stringByReplacingOccurrencesOfString:@"+"
|
||||
withString:@"%20"];
|
||||
// NB. @c queryItems are already percent decoded
|
||||
NSArray<NSURLQueryItem *> *queryItems = components.queryItems;
|
||||
for (NSURLQueryItem *queryItem in queryItems) {
|
||||
[self addParameter:queryItem.name value:queryItem.value];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for iOS 7
|
||||
NSString *query = URL.query;
|
||||
// As OAuth uses application/x-www-form-urlencoded encoding, interprets '+' as a space
|
||||
// in addition to regular percent decoding. https://url.spec.whatwg.org/#urlencoded-parsing
|
||||
query = [query stringByReplacingOccurrencesOfString:@"+" withString:@"%20"];
|
||||
|
||||
NSArray<NSString *> *queryParts = [query componentsSeparatedByString:@"&"];
|
||||
for (NSString *queryPart in queryParts) {
|
||||
NSRange equalsRange = [queryPart rangeOfString:@"="];
|
||||
if (equalsRange.location == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
NSString *name = [queryPart substringToIndex:equalsRange.location];
|
||||
name = name.stringByRemovingPercentEncoding;
|
||||
NSString *value = [queryPart substringFromIndex:equalsRange.location + equalsRange.length];
|
||||
value = value.stringByRemovingPercentEncoding;
|
||||
[self addParameter:name value:value];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)parameters {
|
||||
return _parameters.allKeys;
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, NSObject<NSCopying> *> *)dictionaryValue {
|
||||
// This method will flatten arrays in our @c _parameters' values if only one value exists.
|
||||
NSMutableDictionary<NSString *, NSObject<NSCopying> *> *values = [NSMutableDictionary dictionary];
|
||||
for (NSString *parameter in _parameters.allKeys) {
|
||||
NSArray<NSString *> *value = _parameters[parameter];
|
||||
if (value.count == 1) {
|
||||
values[parameter] = [value.firstObject copy];
|
||||
} else {
|
||||
values[parameter] = [value copy];
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)valuesForParameter:(NSString *)parameter {
|
||||
return _parameters[parameter];
|
||||
}
|
||||
|
||||
- (void)addParameter:(NSString *)parameter value:(NSString *)value {
|
||||
NSMutableArray<NSString *> *parameterValues = _parameters[parameter];
|
||||
if (!parameterValues) {
|
||||
parameterValues = [NSMutableArray array];
|
||||
_parameters[parameter] = parameterValues;
|
||||
}
|
||||
[parameterValues addObject:value];
|
||||
}
|
||||
|
||||
- (void)addParameters:(NSDictionary<NSString *, NSString *> *)parameters {
|
||||
for (NSString *parameterName in parameters.allKeys) {
|
||||
[self addParameter:parameterName value:parameters[parameterName]];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Builds a query items array that can be set to @c NSURLComponents.queryItems
|
||||
@discussion The parameter names and values are NOT URL encoded.
|
||||
@return An array of unencoded @c NSURLQueryItem objects.
|
||||
*/
|
||||
- (NSMutableArray<NSURLQueryItem *> *)queryItems NS_AVAILABLE(10.10, 8.0) {
|
||||
NSMutableArray<NSURLQueryItem *> *queryParameters = [NSMutableArray array];
|
||||
for (NSString *parameterName in _parameters.allKeys) {
|
||||
NSArray<NSString *> *values = _parameters[parameterName];
|
||||
for (NSString *value in values) {
|
||||
NSURLQueryItem *item = [NSURLQueryItem queryItemWithName:parameterName value:value];
|
||||
[queryParameters addObject:item];
|
||||
}
|
||||
}
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
+ (NSMutableCharacterSet *)URLParamValueAllowedCharacters {
|
||||
// Starts with the standard URL-allowed character set.
|
||||
NSMutableCharacterSet *allowedParamCharacters =
|
||||
[[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
|
||||
// Removes additional characters we don't want to see in the query component.
|
||||
[allowedParamCharacters removeCharactersInString:kQueryStringParamAdditionalDisallowedCharacters];
|
||||
return allowedParamCharacters;
|
||||
}
|
||||
|
||||
/*! @brief Builds a query string that can be set to @c NSURLComponents.percentEncodedQuery
|
||||
@discussion This string is percent encoded, and shouldn't be used with
|
||||
@c NSURLComponents.query.
|
||||
@return An percentage encoded query string.
|
||||
*/
|
||||
- (NSString *)percentEncodedQueryString {
|
||||
NSMutableArray<NSString *> *parameterizedValues = [NSMutableArray array];
|
||||
|
||||
// Starts with the standard URL-allowed character set.
|
||||
NSMutableCharacterSet *allowedParamCharacters = [[self class] URLParamValueAllowedCharacters];
|
||||
|
||||
for (NSString *parameterName in _parameters.allKeys) {
|
||||
NSString *encodedParameterName =
|
||||
[parameterName stringByAddingPercentEncodingWithAllowedCharacters:allowedParamCharacters];
|
||||
|
||||
NSArray<NSString *> *values = _parameters[parameterName];
|
||||
for (NSString *value in values) {
|
||||
NSString *encodedValue =
|
||||
[value stringByAddingPercentEncodingWithAllowedCharacters:allowedParamCharacters];
|
||||
NSString *parameterizedValue =
|
||||
[NSString stringWithFormat:@"%@=%@", encodedParameterName, encodedValue];
|
||||
[parameterizedValues addObject:parameterizedValue];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *queryString = [parameterizedValues componentsJoinedByString:@"&"];
|
||||
return queryString;
|
||||
}
|
||||
|
||||
- (NSString *)URLEncodedParameters {
|
||||
// If NSURLQueryItem is available, uses it for constructing the encoded parameters. (iOS 8+)
|
||||
if (@available(iOS 8.0, macOS 10.10, *)) {
|
||||
if (!gOIDURLQueryComponentForceIOS7Handling) {
|
||||
NSURLComponents *components = [[NSURLComponents alloc] init];
|
||||
components.queryItems = [self queryItems];
|
||||
NSString *encodedQuery = components.percentEncodedQuery;
|
||||
// NSURLComponents.percentEncodedQuery creates a validly escaped URL query component, but
|
||||
// doesn't encode the '+' leading to potential ambiguity with application/x-www-form-urlencoded
|
||||
// encoding. Percent encodes '+' to avoid this ambiguity.
|
||||
encodedQuery = [encodedQuery stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
|
||||
return encodedQuery;
|
||||
}
|
||||
}
|
||||
|
||||
// else, falls back to building query string manually (iOS 7)
|
||||
return [self percentEncodedQueryString];
|
||||
}
|
||||
|
||||
- (NSURL *)URLByReplacingQueryInURL:(NSURL *)URL {
|
||||
NSURLComponents *components =
|
||||
[NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
|
||||
|
||||
// Replaces encodedQuery component
|
||||
NSString *queryString = [self URLEncodedParameters];
|
||||
components.percentEncodedQuery = queryString;
|
||||
|
||||
NSURL *URLWithParameters = components.URL;
|
||||
return URLWithParameters;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject overrides
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"<%@: %p, parameters: %@>",
|
||||
NSStringFromClass([self class]),
|
||||
(void *)self,
|
||||
_parameters];
|
||||
}
|
||||
|
||||
@end
|
||||
40
Pods/AppAuth/Source/AppAuthCore/OIDURLSessionProvider.h
generated
Normal file
40
Pods/AppAuth/Source/AppAuthCore/OIDURLSessionProvider.h
generated
Normal file
@ -0,0 +1,40 @@
|
||||
/*! @file OIDURLSessionProvider.h
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 A NSURLSession provider that allows clients to provide custom implementation
|
||||
for NSURLSession
|
||||
*/
|
||||
@interface OIDURLSessionProvider : NSObject
|
||||
|
||||
/*! @brief Obtains the current @c NSURLSession; using the +[NSURLSession sharedSession] if
|
||||
no custom implementation is provided.
|
||||
@return NSURLSession object to be used for making network requests.
|
||||
*/
|
||||
+ (NSURLSession *)session;
|
||||
|
||||
/*! @brief Allows library consumers to change the @c NSURLSession instance used to make
|
||||
network requests.
|
||||
@param session The @c NSURLSession instance that should be used for making network requests.
|
||||
*/
|
||||
+ (void)setSession:(NSURLSession *)session;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
39
Pods/AppAuth/Source/AppAuthCore/OIDURLSessionProvider.m
generated
Normal file
39
Pods/AppAuth/Source/AppAuthCore/OIDURLSessionProvider.m
generated
Normal file
@ -0,0 +1,39 @@
|
||||
/*! @file OIDURLSessionProvider.m
|
||||
@brief AppAuth iOS SDK
|
||||
@copyright
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
@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 "OIDURLSessionProvider.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSURLSession *__nullable gURLSession;
|
||||
|
||||
@implementation OIDURLSessionProvider
|
||||
|
||||
+ (NSURLSession *)session {
|
||||
if (!gURLSession) {
|
||||
gURLSession = [NSURLSession sharedSession];
|
||||
}
|
||||
return gURLSession;
|
||||
}
|
||||
|
||||
+ (void)setSession:(NSURLSession *)session {
|
||||
NSAssert(session, @"Parameter: |session| must be non-nil.");
|
||||
gURLSession = session;
|
||||
}
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
99
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMAppAuthFetcherAuthorization+Keychain.m
generated
Normal file
99
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMAppAuthFetcherAuthorization+Keychain.m
generated
Normal file
@ -0,0 +1,99 @@
|
||||
/*! @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 "GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization+Keychain.h"
|
||||
|
||||
#import "GTMAppAuth/Sources/Public/GTMAppAuth/GTMKeychain.h"
|
||||
|
||||
@implementation GTMAppAuthFetcherAuthorization (Keychain)
|
||||
|
||||
+ (GTMAppAuthFetcherAuthorization *)authorizationFromKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMAppAuthFetcherAuthorization authorizationFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (GTMAppAuthFetcherAuthorization *)authorizationFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
NSData *passwordData = [GTMKeychain passwordDataFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:useDataProtectionKeychain];
|
||||
if (!passwordData) {
|
||||
return nil;
|
||||
}
|
||||
GTMAppAuthFetcherAuthorization *authorization;
|
||||
if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *)) {
|
||||
authorization = (GTMAppAuthFetcherAuthorization *)
|
||||
[NSKeyedUnarchiver unarchivedObjectOfClass:[GTMAppAuthFetcherAuthorization class]
|
||||
fromData:passwordData
|
||||
error:nil];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
authorization = (GTMAppAuthFetcherAuthorization *)
|
||||
[NSKeyedUnarchiver unarchiveObjectWithData:passwordData];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
return authorization;
|
||||
}
|
||||
|
||||
+ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMAppAuthFetcherAuthorization removeAuthorizationFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
return [GTMKeychain removePasswordFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:useDataProtectionKeychain];
|
||||
}
|
||||
|
||||
+ (BOOL)saveAuthorization:(GTMAppAuthFetcherAuthorization *)auth
|
||||
toKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMAppAuthFetcherAuthorization saveAuthorization:auth
|
||||
toKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (BOOL)saveAuthorization:(GTMAppAuthFetcherAuthorization *)auth
|
||||
toKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
NSData *authorizationData;
|
||||
if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *)) {
|
||||
authorizationData = [NSKeyedArchiver archivedDataWithRootObject:auth
|
||||
requiringSecureCoding:YES
|
||||
error:nil];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
authorizationData = [NSKeyedArchiver archivedDataWithRootObject:auth];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
return [GTMKeychain savePasswordDataToKeychainForName:keychainItemName
|
||||
passwordData:authorizationData
|
||||
useDataProtectionKeychain:useDataProtectionKeychain];
|
||||
}
|
||||
|
||||
@end
|
||||
497
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMAppAuthFetcherAuthorization.m
generated
Normal file
497
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMAppAuthFetcherAuthorization.m
generated
Normal file
@ -0,0 +1,497 @@
|
||||
/*! @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 "GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization.h"
|
||||
|
||||
#if SWIFT_PACKAGE || GTMAPPAUTH_USE_MODULAR_IMPORT
|
||||
@import AppAuthCore;
|
||||
#elif GTMAPPAUTH_USER_IMPORTS
|
||||
#import "AppAuthCore.h"
|
||||
#else
|
||||
#import <AppAuth/AppAuthCore.h>
|
||||
#endif
|
||||
|
||||
#define GTMOAuth2AssertValidSelector GTMSessionFetcherAssertValidSelector
|
||||
|
||||
/*! @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;
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
- (void)authorizeRequest:(NSMutableURLRequest *)request
|
||||
delegate:(id)delegate
|
||||
didFinishSelector:(SEL)sel {
|
||||
#pragma clang diagnostic pop
|
||||
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
|
||||
326
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMKeychain.m
generated
Normal file
326
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMKeychain.m
generated
Normal file
@ -0,0 +1,326 @@
|
||||
/*! @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 "GTMAppAuth/Sources/Public/GTMAppAuth/GTMKeychain.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
|
||||
/*! @brief Keychain helper class.
|
||||
*/
|
||||
@interface GTMAppAuthGTMOAuth2Keychain : NSObject
|
||||
|
||||
// When set to YES, all Keychain queries will have
|
||||
// kSecUseDataProtectionKeychain set to true on macOS 10.15+. Defaults to NO.
|
||||
@property(nonatomic) BOOL useDataProtectionKeychain;
|
||||
|
||||
+ (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
|
||||
|
||||
static NSString *const kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName = @"OAuth";
|
||||
|
||||
@implementation GTMKeychain
|
||||
|
||||
+ (BOOL)removePasswordFromKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMKeychain removePasswordFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (BOOL)removePasswordFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain];
|
||||
keychain.useDataProtectionKeychain = useDataProtectionKeychain;
|
||||
return [keychain removePasswordForService:keychainItemName
|
||||
account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName
|
||||
error:nil];
|
||||
}
|
||||
|
||||
+ (NSString *)passwordFromKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMKeychain passwordFromKeychainForName:keychainItemName useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (NSString *)passwordFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain];
|
||||
keychain.useDataProtectionKeychain = useDataProtectionKeychain;
|
||||
NSError *error;
|
||||
NSString *password =
|
||||
[keychain passwordForService:keychainItemName
|
||||
account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName
|
||||
error:&error];
|
||||
return password;
|
||||
}
|
||||
|
||||
+ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName
|
||||
password:(NSString *)password {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMKeychain savePasswordToKeychainForName:keychainItemName
|
||||
password:password
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName
|
||||
password:(NSString *)password
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
CFTypeRef accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain];
|
||||
keychain.useDataProtectionKeychain = useDataProtectionKeychain;
|
||||
return [keychain setPassword:password
|
||||
forService:keychainItemName
|
||||
accessibility:accessibility
|
||||
account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
+ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName
|
||||
passwordData:(NSData *)password {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMKeychain savePasswordDataToKeychainForName:keychainItemName
|
||||
passwordData:password
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName
|
||||
passwordData:(NSData *)password
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
CFTypeRef accessibility = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain];
|
||||
keychain.useDataProtectionKeychain = useDataProtectionKeychain;
|
||||
return [keychain setPasswordData:password
|
||||
forService:keychainItemName
|
||||
accessibility:accessibility
|
||||
account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
+ (NSData *)passwordDataFromKeychainForName:(NSString *)keychainItemName {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
return [GTMKeychain passwordDataFromKeychainForName:keychainItemName
|
||||
useDataProtectionKeychain:NO];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
+ (NSData *)passwordDataFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain {
|
||||
GTMAppAuthGTMOAuth2Keychain *keychain = [GTMAppAuthGTMOAuth2Keychain defaultKeychain];
|
||||
keychain.useDataProtectionKeychain = useDataProtectionKeychain;
|
||||
NSError *error;
|
||||
NSData *password =
|
||||
[keychain passwordDataForService:keychainItemName
|
||||
account:kGTMAppAuthFetcherAuthorizationGTMOAuth2AccountName
|
||||
error:&error];
|
||||
return password;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
typedef NS_ENUM(NSInteger, GTMAppAuthFetcherAuthorizationGTMAppAuthGTMOAuth2KeychainError) {
|
||||
GTMAppAuthGTMOAuth2KeychainErrorBadArguments = -1301,
|
||||
GTMAppAuthGTMOAuth2KeychainErrorNoPassword = -1302
|
||||
};
|
||||
|
||||
NSString *const kGTMAppAuthFetcherAuthorizationGTMOAuth2KeychainErrorDomain =
|
||||
@"com.google.GTMOAuthKeychain";
|
||||
|
||||
static GTMAppAuthGTMOAuth2Keychain* gGTMAppAuthFetcherAuthorizationGTMOAuth2DefaultKeychain = nil;
|
||||
|
||||
@implementation GTMAppAuthGTMOAuth2Keychain
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_useDataProtectionKeychain = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (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;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)keychainQueryForService:(NSString *)service account:(NSString *)account {
|
||||
NSMutableDictionary *query =
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword, (id)kSecClass,
|
||||
account, (id)kSecAttrAccount,
|
||||
service, (id)kSecAttrService,
|
||||
nil];
|
||||
// kSecUseDataProtectionKeychain is a no-op on platforms other than macOS 10.15+. For clarity, we
|
||||
// set it here only when supported by the Apple SDK and when relevant at runtime.
|
||||
#if TARGET_OS_OSX && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
|
||||
if (@available(macOS 10.15, *)) {
|
||||
if (self.useDataProtectionKeychain) {
|
||||
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecUseDataProtectionKeychain];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return query;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (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
|
||||
331
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMOAuth2KeychainCompatibility.m
generated
Normal file
331
Pods/GTMAppAuth/GTMAppAuth/Sources/GTMOAuth2KeychainCompatibility.m
generated
Normal file
@ -0,0 +1,331 @@
|
||||
/*! @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 "GTMAppAuth/Sources/Public/GTMAppAuth/GTMOAuth2KeychainCompatibility.h"
|
||||
|
||||
#import "GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization.h"
|
||||
#import "GTMAppAuth/Sources/Public/GTMAppAuth/GTMKeychain.h"
|
||||
|
||||
#if SWIFT_PACKAGE || GTMAPPAUTH_USE_MODULAR_IMPORT
|
||||
@import AppAuthCore;
|
||||
@import GTMSessionFetcherCore;
|
||||
#elif GTMAPPAUTH_USER_IMPORTS
|
||||
#import "AppAuthCore.h"
|
||||
#import "GTMSessionFetcher.h"
|
||||
#else
|
||||
#import <AppAuth/AppAuthCore.h>
|
||||
#import <GTMSessionFetcher/GTMSessionFetcher.h>
|
||||
#endif
|
||||
|
||||
// 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
|
||||
22
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuth.h
generated
Normal file
22
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuth.h
generated
Normal file
@ -0,0 +1,22 @@
|
||||
/*! @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"
|
||||
#import "GTMKeychain.h"
|
||||
#import "GTMOAuth2KeychainCompatibility.h"
|
||||
89
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization+Keychain.h
generated
Normal file
89
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization+Keychain.h
generated
Normal file
@ -0,0 +1,89 @@
|
||||
/*! @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 Attempts to create a @c GTMAppAuthFetcherAuthorization from data stored in the keychain
|
||||
in GTMAppAuth format. Note that if you choose to start using the data protection keychain on
|
||||
macOS, any items previously created will not be accessible without migration.
|
||||
@param keychainItemName The keychain name.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return A @c GTMAppAuthFetcherAuthorization object, or nil.
|
||||
*/
|
||||
+ (nullable GTMAppAuthFetcherAuthorization *)
|
||||
authorizationFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @brief Removes a stored authorization state.
|
||||
@param keychainItemName The keychain name.
|
||||
@return YES if the tokens were removed successfully (or didn't exist).
|
||||
*/
|
||||
+ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName;
|
||||
|
||||
/*! @brief Removes a stored authorization state. Note that if you choose to start using the data
|
||||
protection keychain on macOS, any items previously created will not be accessible without
|
||||
migration.
|
||||
@param keychainItemName The keychain name.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return YES if the tokens were removed successfully (or didn't exist).
|
||||
*/
|
||||
+ (BOOL)removeAuthorizationFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain
|
||||
API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @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;
|
||||
|
||||
/*! @brief Saves the authorization state to the keychain, in GTMAppAuth format. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param auth The authorization to save.
|
||||
@param keychainItemName The keychain name.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return YES when the state was saved successfully.
|
||||
*/
|
||||
+ (BOOL)saveAuthorization:(GTMAppAuthFetcherAuthorization *)auth
|
||||
toKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain API_AVAILABLE(macosx(10.15));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
160
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization.h
generated
Normal file
160
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMAppAuthFetcherAuthorization.h
generated
Normal file
@ -0,0 +1,160 @@
|
||||
/*! @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.
|
||||
*/
|
||||
|
||||
#if !defined(__has_include)
|
||||
#error "__has_include not available."
|
||||
#elif __has_include(<GTMSessionFetcher/GTMSessionFetcher.h>)
|
||||
#import <GTMSessionFetcher/GTMSessionFetcher.h>
|
||||
#elif __has_include("../GTMSessionFetcher.h")
|
||||
#import "../GTMSessionFetcher.h"
|
||||
#else
|
||||
# error "Failed to find GTMSessionFetcher"
|
||||
#endif
|
||||
|
||||
@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.
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
@interface GTMAppAuthFetcherAuthorization : NSObject <GTMFetcherAuthorizationProtocol,
|
||||
NSSecureCoding>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
/*! @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
|
||||
126
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMKeychain.h
generated
Normal file
126
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMKeychain.h
generated
Normal file
@ -0,0 +1,126 @@
|
||||
/*! @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 if the password string was saved successfully.
|
||||
*/
|
||||
+ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName
|
||||
password:(NSString *)password;
|
||||
|
||||
/*! @brief Saves the password string to the keychain with the given identifier. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param keychainItemName Keychain name of the item.
|
||||
@param password Password string to save.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return YES if the password string was saved successfully.
|
||||
*/
|
||||
+ (BOOL)savePasswordToKeychainForName:(NSString *)keychainItemName
|
||||
password:(NSString *)password
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @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 Loads the password string from the keychain with the given identifier. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param keychainItemName Keychain name of the item.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return The password string at the given identifier, or nil.
|
||||
*/
|
||||
+ (nullable NSString *)passwordFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain
|
||||
API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @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 if the password data was saved successfully.
|
||||
*/
|
||||
+ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName
|
||||
passwordData:(NSData *)passwordData;
|
||||
|
||||
/*! @brief Saves the password data to the keychain with the given identifier. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param keychainItemName Keychain name of the item.
|
||||
@param passwordData Password data to save.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return YES if the password data was saved successfully.
|
||||
*/
|
||||
+ (BOOL)savePasswordDataToKeychainForName:(NSString *)keychainItemName
|
||||
passwordData:(NSData *)passwordData
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain
|
||||
API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @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 Loads the password data from the keychain with the given identifier. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param keychainItemName Keychain name of the item.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return The password data at the given identifier, or nil.
|
||||
*/
|
||||
+ (nullable NSData *)passwordDataFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain
|
||||
API_AVAILABLE(macosx(10.15));
|
||||
|
||||
/*! @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;
|
||||
|
||||
/*! @brief Removes stored password string, such as when the user signs out. Note that if you
|
||||
choose to start using the data protection keychain on macOS, any items previously created
|
||||
will not be accessible without migration.
|
||||
@param keychainItemName Keychain name of the item.
|
||||
@param useDataProtectionKeychain A Boolean value that indicates whether to use the data
|
||||
protection keychain on macOS 10.15+.
|
||||
@return YES if the password string was removed successfully (or didn't exist).
|
||||
*/
|
||||
+ (BOOL)removePasswordFromKeychainForName:(NSString *)keychainItemName
|
||||
useDataProtectionKeychain:(BOOL)useDataProtectionKeychain
|
||||
API_AVAILABLE(macosx(10.15));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
133
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMOAuth2KeychainCompatibility.h
generated
Normal file
133
Pods/GTMAppAuth/GTMAppAuth/Sources/Public/GTMAppAuth/GTMOAuth2KeychainCompatibility.h
generated
Normal file
@ -0,0 +1,133 @@
|
||||
/*! @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 <Foundation/Foundation.h>
|
||||
|
||||
@class GTMAppAuthFetcherAuthorization;
|
||||
|
||||
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
|
||||
202
Pods/GTMAppAuth/LICENSE
generated
Normal file
202
Pods/GTMAppAuth/LICENSE
generated
Normal file
@ -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.
|
||||
418
Pods/GTMAppAuth/README.md
generated
Normal file
418
Pods/GTMAppAuth/README.md
generated
Normal file
@ -0,0 +1,418 @@
|
||||
[](https://cocoapods.org/pods/GTMAppAuth)
|
||||
[](https://cocoapods.org/pods/GTMAppAuth)
|
||||
[](https://cocoapods.org/pods/GTMAppAuth)
|
||||
[](https://github.com/google/GTMAppAuth/actions/workflows/tests.yml)
|
||||
|
||||
# GTMAppAuth for Apple Platforms
|
||||
|
||||
GTMAppAuth enables you to use [AppAuth](https://github.com/openid/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 on iOS, macOS, tvOS, and watchOS by providing an implementation of
|
||||
[`GTMFetcherAuthorizationProtocol`](https://github.com/google/gtm-session-fetcher/blob/2a3b5264108e80d62003b770ff02eb7364ff1365/Source/GTMSessionFetcher.h#L660)
|
||||
for authorizing requests with AppAuth.
|
||||
|
||||
GTMAppAuth is an alternative authorizer to [GTMOAuth2](https://github.com/google/gtm-oauth2)
|
||||
. 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://datatracker.ietf.org/doc/html/rfc8252).
|
||||
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);
|
||||
}];
|
||||
```
|
||||
|
||||
### Saving to the Keychain
|
||||
|
||||
You can easily save `GTMAppAuthFetcherAuthorization` instances to the Keychain using
|
||||
the included `GTMAppAuthFetcherAuthorization+Keychain` category.
|
||||
|
||||
```objc
|
||||
// Save to Keychain
|
||||
[GTMAppAuthFetcherAuthorization saveAuthorization:_authorization
|
||||
toKeychainForName:kGTMAppAuthExampleAuthorizerKey];
|
||||
|
||||
// Restore from Keychain
|
||||
GTMAppAuthFetcherAuthorization* authorization =
|
||||
[GTMAppAuthFetcherAuthorization authorizationFromKeychainForName:kGTMAppAuthExampleAuthorizerKey];
|
||||
|
||||
// Remove from Keychain
|
||||
[GTMAppAuthFetcherAuthorization
|
||||
removeAuthorizationFromKeychainForName:kGTMAppAuthExampleAuthorizerKey];
|
||||
```
|
||||
|
||||
#### Keychain Storage
|
||||
|
||||
`GTMAppAuthFetcherAuthorization` instances are stored using Keychain items of the
|
||||
[`kSecClassGenericPassword`](https://developer.apple.com/documentation/security/ksecclassgenericpassword?language=objc)
|
||||
class with a [`kSecAttrAccount`](https://developer.apple.com/documentation/security/ksecattraccount?language=objc)
|
||||
value of "OAuth" and a developer supplied value for [`kSecAttrService`](https://developer.apple.com/documentation/security/ksecattrservice?language=objc).
|
||||
For this use of generic password items, the combination of account and service
|
||||
values acts as the
|
||||
[primary key](https://developer.apple.com/documentation/security/1542001-security_framework_result_codes/errsecduplicateitem?language=objc)
|
||||
of the Keychain items. The
|
||||
[`kSecAttrAccessible`](https://developer.apple.com/documentation/security/ksecattraccessible?language=objc)
|
||||
key is set to
|
||||
[`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`](https://developer.apple.com/documentation/security/ksecattraccessibleafterfirstunlockthisdeviceonly?language=objc)
|
||||
in order to allow background access after initial device unlock following a
|
||||
restart. A [keyed archive](https://developer.apple.com/documentation/foundation/nskeyedarchiver?language=objc)
|
||||
representation of the relevant `GTMAppAuthFetcherAuthorization` instance is supplied as the value for
|
||||
[`kSecValueData`](https://developer.apple.com/documentation/security/ksecvaluedata?language=objc)
|
||||
and this is encrypted and stored by
|
||||
[Keychain Services](https://developer.apple.com/documentation/security/keychain_services?language=objc).
|
||||
|
||||
For macOS, two Keychain storage options are available: the traditional file-based Keychain storage
|
||||
which uses access control lists and the more modern [data protection keychain storage](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain?language=objc)
|
||||
which uses Keychain access control groups. By default, GTMAppAuth uses the file-based Keychain storage on macOS. You may opt into using data protection keychain storage by using the parameter
|
||||
`useDataProtectionKeychain:YES` in your method calls. Note that Keychain items stored via one
|
||||
storage type will not be available via the other and macOS apps that choose to use the data
|
||||
protection Keychain will need to be signed in order for Keychain operations to succeed.
|
||||
|
||||
#### GTMOAuth2 Compatibility
|
||||
|
||||
To assist the migration from GTMOAuth2 to GTMAppAuth, GTMOAuth2-compatible
|
||||
Keychain methods are provided in `GTMOAuth2KeychainCompatibility`.
|
||||
|
||||
```objc
|
||||
// Restore from Keychain
|
||||
GTMAppAuthFetcherAuthorization *auth =
|
||||
[GTMOAuth2KeychainCompatibility authForGoogleFromKeychainForName:kKeychainItemName
|
||||
clientID:clientID
|
||||
clientSecret:clientSecret];
|
||||
|
||||
// Remove from Keychain
|
||||
[GTMOAuth2KeychainCompatibility removeAuthFromKeychainForName:kKeychainItemName];
|
||||
```
|
||||
|
||||
You can also save to GTMOAuth2 format, though this is discouraged (you
|
||||
should save in GTMAppAuth format as described above).
|
||||
|
||||
```objc
|
||||
// Save 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];
|
||||
}
|
||||
}
|
||||
```
|
||||
2
Pods/GTMSessionFetcher/README.md
generated
2
Pods/GTMSessionFetcher/README.md
generated
@ -3,7 +3,7 @@
|
||||
**Project site** <https://github.com/google/gtm-session-fetcher><br>
|
||||
**Discussion group** <http://groups.google.com/group/google-toolbox-for-mac>
|
||||
|
||||
[](https://travis-ci.org/google/gtm-session-fetcher)
|
||||
[](https://github.com/google/gtm-session-fetcher/actions/workflows/main.yml)
|
||||
|
||||
`GTMSessionFetcher` makes it easy for Cocoa applications to perform http
|
||||
operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its
|
||||
|
||||
21
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.h
generated
21
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.h
generated
@ -24,16 +24,17 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// These will be removed in the near future, folks should move off of them.
|
||||
#ifndef GTM_NONNULL
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Avoid multiple declaration of this class.
|
||||
@ -45,7 +46,7 @@
|
||||
|
||||
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
||||
|
||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray GTM_NONNULL((1));
|
||||
+ (nonnull instancetype)streamWithArray:(nonnull NSArray *)dataArray;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
14
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.m
generated
14
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.m
generated
@ -20,18 +20,18 @@
|
||||
#import "GTMGatherInputStream.h"
|
||||
|
||||
@implementation GTMGatherInputStream {
|
||||
NSArray *_dataArray; // NSDatas that should be "gathered" and streamed.
|
||||
NSArray *_dataArray; // NSDatas that should be "gathered" and streamed.
|
||||
NSUInteger _arrayIndex; // Index in the array of the current NSData.
|
||||
long long _dataOffset; // Offset in the current NSData we are processing.
|
||||
long long _dataOffset; // Offset in the current NSData we are processing.
|
||||
NSStreamStatus _streamStatus;
|
||||
id<NSStreamDelegate> __weak _delegate; // Stream delegate, defaults to self.
|
||||
}
|
||||
|
||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray {
|
||||
return [(GTMGatherInputStream *)[self alloc] initWithArray:dataArray];
|
||||
+ (instancetype)streamWithArray:(NSArray *)dataArray {
|
||||
return [[self alloc] initWithDataArray:dataArray];
|
||||
}
|
||||
|
||||
- (instancetype)initWithArray:(NSArray *)dataArray {
|
||||
- (instancetype)initWithDataArray:(NSArray *)dataArray {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_dataArray = dataArray;
|
||||
@ -108,7 +108,7 @@
|
||||
NSUInteger dataBytesLeft = dataLen - (NSUInteger)_dataOffset;
|
||||
|
||||
NSUInteger bytesToCopy = MIN(bytesRemaining, dataBytesLeft);
|
||||
NSRange range = NSMakeRange((NSUInteger) _dataOffset, bytesToCopy);
|
||||
NSRange range = NSMakeRange((NSUInteger)_dataOffset, bytesToCopy);
|
||||
|
||||
[data getBytes:(buffer + bytesRead) range:range];
|
||||
|
||||
@ -168,7 +168,7 @@
|
||||
_arrayIndex = 0;
|
||||
_dataOffset = absoluteOffset;
|
||||
for (NSData *data in _dataArray) {
|
||||
long long dataLen = (long long) data.length;
|
||||
long long dataLen = (long long)data.length;
|
||||
if (dataLen > _dataOffset) {
|
||||
break;
|
||||
}
|
||||
|
||||
110
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.h
generated
110
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.h
generated
@ -22,34 +22,33 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// These will be removed in the near future, folks should move off of them.
|
||||
#ifndef GTM_NONNULL
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GTM_DECLARE_GENERICS
|
||||
#if __has_feature(objc_generics)
|
||||
#define GTM_DECLARE_GENERICS 1
|
||||
#else
|
||||
#define GTM_DECLARE_GENERICS 0
|
||||
#endif
|
||||
#if __has_feature(objc_generics)
|
||||
#define GTM_DECLARE_GENERICS 1
|
||||
#else
|
||||
#define GTM_DECLARE_GENERICS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GTM_NSArrayOf
|
||||
#if GTM_DECLARE_GENERICS
|
||||
#define GTM_NSArrayOf(value) NSArray<value>
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||
#else
|
||||
#define GTM_NSArrayOf(value) NSArray
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||
#endif // GTM_DECLARE_GENERICS
|
||||
#if GTM_DECLARE_GENERICS
|
||||
#define GTM_NSArrayOf(value) NSArray<value>
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||
#else
|
||||
#define GTM_NSArrayOf(value) NSArray
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||
#endif // GTM_DECLARE_GENERICS
|
||||
#endif // GTM_NSArrayOf
|
||||
|
||||
|
||||
@ -58,12 +57,13 @@
|
||||
// +[GTMMIMEDocument MIMEPartsWithBoundary:data:] returns an array of these.
|
||||
@interface GTMMIMEDocumentPart : NSObject
|
||||
|
||||
@property(nonatomic, readonly) GTM_NSDictionaryOf(NSString *, NSString *) *headers;
|
||||
@property(nonatomic, readonly) NSData *headerData;
|
||||
@property(nonatomic, readonly) NSData *body;
|
||||
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *headers;
|
||||
@property(nonatomic, readonly, nonnull) NSData *headerData;
|
||||
@property(nonatomic, readonly, nonnull) NSData *body;
|
||||
@property(nonatomic, readonly) NSUInteger length;
|
||||
|
||||
+ (instancetype)partWithHeaders:(NSDictionary *)headers body:(NSData *)body;
|
||||
+ (nonnull instancetype)partWithHeaders:(nullable NSDictionary *)headers
|
||||
body:(nonnull NSData *)body;
|
||||
|
||||
@end
|
||||
|
||||
@ -73,24 +73,24 @@
|
||||
//
|
||||
// When creating a MIME document from parts, this is typically calculated
|
||||
// automatically after all parts have been added.
|
||||
@property(nonatomic, copy) NSString *boundary;
|
||||
@property(nonatomic, copy, null_resettable) NSString *boundary;
|
||||
|
||||
#pragma mark - Methods for Creating a MIME Document
|
||||
|
||||
+ (instancetype)MIMEDocument;
|
||||
+ (nonnull instancetype)MIMEDocument;
|
||||
|
||||
// Adds a new part to this mime document with the given headers and body.
|
||||
// The headers keys and values should be NSStrings.
|
||||
// Adding a part may cause the boundary string to change.
|
||||
- (void)addPartWithHeaders:(GTM_NSDictionaryOf(NSString *, NSString *) *)headers
|
||||
body:(NSData *)body GTM_NONNULL((1,2));
|
||||
- (void)addPartWithHeaders:(nonnull NSDictionary<NSString *, NSString *> *)headers
|
||||
body:(nonnull NSData *)body;
|
||||
|
||||
// An inputstream that can be used to efficiently read the contents of the MIME document.
|
||||
//
|
||||
// Any parameter may be null if the result is not wanted.
|
||||
- (void)generateInputStream:(NSInputStream **)outStream
|
||||
length:(unsigned long long *)outLength
|
||||
boundary:(NSString **)outBoundary;
|
||||
- (void)generateInputStream:(NSInputStream *_Nullable *_Nullable)outStream
|
||||
length:(unsigned long long *_Nullable)outLength
|
||||
boundary:(NSString *_Nullable *_Nullable)outBoundary;
|
||||
|
||||
// A dispatch_data_t with the contents of the MIME document.
|
||||
//
|
||||
@ -98,12 +98,12 @@
|
||||
// may be cast directly to NSData *.
|
||||
//
|
||||
// Any parameter may be null if the result is not wanted.
|
||||
- (void)generateDispatchData:(dispatch_data_t *)outDispatchData
|
||||
length:(unsigned long long *)outLength
|
||||
boundary:(NSString **)outBoundary;
|
||||
- (void)generateDispatchData:(dispatch_data_t _Nullable *_Nullable)outDispatchData
|
||||
length:(unsigned long long *_Nullable)outLength
|
||||
boundary:(NSString *_Nullable *_Nullable)outBoundary;
|
||||
|
||||
// Utility method for making a header section, including trailing newlines.
|
||||
+ (NSData *)dataWithHeaders:(GTM_NSDictionaryOf(NSString *, NSString *) *)headers;
|
||||
+ (nonnull NSData *)dataWithHeaders:(nullable NSDictionary<NSString *, NSString *> *)headers;
|
||||
|
||||
#pragma mark - Methods for Parsing a MIME Document
|
||||
|
||||
@ -111,8 +111,14 @@
|
||||
//
|
||||
// Returns an array of GTMMIMEDocumentParts. Returns nil if no part can
|
||||
// be found.
|
||||
+ (GTM_NSArrayOf(GTMMIMEDocumentPart *) *)MIMEPartsWithBoundary:(NSString *)boundary
|
||||
data:(NSData *)fullDocumentData;
|
||||
//
|
||||
// NOTE: if MIME parts in the data are malformed, the resulting array may
|
||||
// still contain GTMMIMEDocumentParts in the position where the malformed
|
||||
// parts appeared; these parts will have an empty NSData body and nil
|
||||
// headers.
|
||||
+ (nullable NSArray<GTMMIMEDocumentPart *> *)MIMEPartsWithBoundary:(nonnull NSString *)boundary
|
||||
data:(nonnull NSData *)
|
||||
fullDocumentData;
|
||||
|
||||
// Utility method for efficiently searching possibly discontiguous NSData
|
||||
// for occurrences of target byte. This method does not "flatten" an NSData
|
||||
@ -120,29 +126,29 @@
|
||||
//
|
||||
// The byte offsets of non-overlapping occurrences of the target are returned as
|
||||
// NSNumbers in the array.
|
||||
+ (void)searchData:(NSData *)data
|
||||
targetBytes:(const void *)targetBytes
|
||||
+ (void)searchData:(nonnull NSData *)data
|
||||
targetBytes:(const void *_Nonnull)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets;
|
||||
foundOffsets:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundOffsets;
|
||||
|
||||
// Utility method to parse header bytes into an NSDictionary.
|
||||
+ (GTM_NSDictionaryOf(NSString *, NSString *) *)headersWithData:(NSData *)data;
|
||||
+ (nullable NSDictionary<NSString *, NSString *> *)headersWithData:(nonnull NSData *)data;
|
||||
|
||||
// ------ UNIT TESTING ONLY BELOW ------
|
||||
|
||||
// Internal methods, exposed for unit testing only.
|
||||
- (void)seedRandomWith:(u_int32_t)seed;
|
||||
|
||||
+ (NSUInteger)findBytesWithNeedle:(const unsigned char *)needle
|
||||
+ (NSUInteger)findBytesWithNeedle:(const unsigned char *_Nonnull)needle
|
||||
needleLength:(NSUInteger)needleLength
|
||||
haystack:(const unsigned char *)haystack
|
||||
haystack:(const unsigned char *_Nonnull)haystack
|
||||
haystackLength:(NSUInteger)haystackLength
|
||||
foundOffset:(NSUInteger *)foundOffset;
|
||||
foundOffset:(NSUInteger *_Nonnull)foundOffset;
|
||||
|
||||
+ (void)searchData:(NSData *)data
|
||||
targetBytes:(const void *)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets
|
||||
foundBlockNumbers:(GTM_NSArrayOf(NSNumber *) **)outFoundBlockNumbers;
|
||||
+ (void)searchData:(nonnull NSData *)data
|
||||
targetBytes:(const void *_Nonnull)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundOffsets
|
||||
foundBlockNumbers:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundBlockNumbers;
|
||||
|
||||
@end
|
||||
|
||||
127
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.m
generated
127
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.m
generated
@ -25,7 +25,7 @@
|
||||
|
||||
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
||||
|
||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray GTM_NONNULL((1));
|
||||
+ (nonnull instancetype)streamWithArray:(nonnull NSArray *)dataArray;
|
||||
|
||||
@end
|
||||
#endif // GTM_GATHERINPUTSTREAM_DECLARED
|
||||
@ -55,9 +55,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
NSData *_bodyData;
|
||||
}
|
||||
|
||||
@synthesize headers = _headers,
|
||||
headerData = _headerData,
|
||||
body = _bodyData;
|
||||
@synthesize headers = _headers, headerData = _headerData, body = _bodyData;
|
||||
|
||||
@dynamic length;
|
||||
|
||||
@ -83,7 +81,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
// null values.
|
||||
NSData *headerData = self.headerData;
|
||||
return (FindBytes(bytes, length, headerData.bytes, headerData.length, NULL) == length ||
|
||||
FindBytes(bytes, length, _bodyData.bytes, _bodyData.length, NULL) == length);
|
||||
FindBytes(bytes, length, _bodyData.bytes, _bodyData.length, NULL) == length);
|
||||
}
|
||||
|
||||
- (NSData *)headerData {
|
||||
@ -102,16 +100,16 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@ %p (headers %lu keys, body %lu bytes)",
|
||||
[self class], self, (unsigned long)_headers.count,
|
||||
(unsigned long)_bodyData.length];
|
||||
return [NSString stringWithFormat:@"%@ %p (headers %lu keys, body %lu bytes)", [self class], self,
|
||||
(unsigned long)_headers.count, (unsigned long)_bodyData.length];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(GTMMIMEDocumentPart *)other {
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (self == other) return YES;
|
||||
if (![other isKindOfClass:[GTMMIMEDocumentPart class]]) return NO;
|
||||
return ((_bodyData == other->_bodyData || [_bodyData isEqual:other->_bodyData])
|
||||
&& (_headers == other->_headers || [_headers isEqual:other->_headers]));
|
||||
GTMMIMEDocumentPart *otherPart = (GTMMIMEDocumentPart *)other;
|
||||
return ((_bodyData == otherPart->_bodyData || [_bodyData isEqual:otherPart->_bodyData]) &&
|
||||
(_headers == otherPart->_headers || [_headers isEqual:otherPart->_headers]));
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
@ -121,10 +119,10 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
@end
|
||||
|
||||
@implementation GTMMIMEDocument {
|
||||
NSMutableArray *_parts; // Ordered array of GTMMIMEDocumentParts.
|
||||
unsigned long long _length; // Length in bytes of the document.
|
||||
NSMutableArray *_parts; // Ordered array of GTMMIMEDocumentParts.
|
||||
unsigned long long _length; // Length in bytes of the document.
|
||||
NSString *_boundary;
|
||||
u_int32_t _randomSeed; // For testing.
|
||||
u_int32_t _randomSeed; // For testing.
|
||||
}
|
||||
|
||||
+ (instancetype)MIMEDocument {
|
||||
@ -140,8 +138,8 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@ %p (%lu parts)",
|
||||
[self class], self, (unsigned long)_parts.count];
|
||||
return [NSString
|
||||
stringWithFormat:@"%@ %p (%lu parts)", [self class], self, (unsigned long)_parts.count];
|
||||
}
|
||||
|
||||
#pragma mark - Joining Parts
|
||||
@ -188,7 +186,6 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
|
||||
const int maxTries = 10; // Arbitrarily chosen maximum attempts.
|
||||
for (int tries = 0; tries < maxTries; ++tries) {
|
||||
|
||||
NSData *data = [_boundary dataUsingEncoding:NSUTF8StringEncoding];
|
||||
const void *dataBytes = data.bytes;
|
||||
NSUInteger dataLen = data.length;
|
||||
@ -198,7 +195,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
if (didCollide) break;
|
||||
}
|
||||
|
||||
if (!didCollide) break; // We're fine, no more attempts needed.
|
||||
if (!didCollide) break; // We're fine, no more attempts needed.
|
||||
|
||||
// Try again with a random number appended.
|
||||
_boundary = [NSString stringWithFormat:@"%@_%08x", kBaseBoundary, [self random]];
|
||||
@ -219,7 +216,6 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
- (void)generateDataArray:(NSMutableArray *)dataArray
|
||||
length:(unsigned long long *)outLength
|
||||
boundary:(NSString **)outBoundary {
|
||||
|
||||
// The input stream is of the form:
|
||||
// --boundary
|
||||
// [part_1_headers]
|
||||
@ -252,7 +248,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
[dataArray addObject:endBoundaryData];
|
||||
length += endBoundaryData.length;
|
||||
|
||||
if (outLength) *outLength = length;
|
||||
if (outLength) *outLength = length;
|
||||
if (outBoundary) *outBoundary = boundary;
|
||||
}
|
||||
|
||||
@ -260,9 +256,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
length:(unsigned long long *)outLength
|
||||
boundary:(NSString **)outBoundary {
|
||||
NSMutableArray *dataArray = outStream ? [NSMutableArray array] : nil;
|
||||
[self generateDataArray:dataArray
|
||||
length:outLength
|
||||
boundary:outBoundary];
|
||||
[self generateDataArray:dataArray length:outLength boundary:outBoundary];
|
||||
|
||||
if (outStream) {
|
||||
Class streamClass = NSClassFromString(@"GTMGatherInputStream");
|
||||
@ -276,9 +270,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
length:(unsigned long long *)outLength
|
||||
boundary:(NSString **)outBoundary {
|
||||
NSMutableArray *dataArray = outDispatchData ? [NSMutableArray array] : nil;
|
||||
[self generateDataArray:dataArray
|
||||
length:outLength
|
||||
boundary:outBoundary];
|
||||
[self generateDataArray:dataArray length:outLength boundary:outBoundary];
|
||||
|
||||
if (outDispatchData) {
|
||||
// Create an empty data accumulator.
|
||||
@ -290,9 +282,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
__block NSData *immutablePartData = [partData copy];
|
||||
dispatch_data_t newDataPart =
|
||||
dispatch_data_create(immutablePartData.bytes, immutablePartData.length, bgQueue, ^{
|
||||
// We want the data retained until this block executes.
|
||||
immutablePartData = nil;
|
||||
});
|
||||
// We want the data retained until this block executes.
|
||||
immutablePartData = nil;
|
||||
});
|
||||
|
||||
if (dataAccumulator == nil) {
|
||||
// First part.
|
||||
@ -308,7 +300,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
|
||||
+ (NSData *)dataWithHeaders:(NSDictionary *)headers {
|
||||
// Generate the header data by coalescing the dictionary as lines of "key: value\r\n".
|
||||
NSMutableString* headerString = [NSMutableString string];
|
||||
NSMutableString *headerString = [NSMutableString string];
|
||||
|
||||
// Sort the header keys so we have a deterministic order for unit testing.
|
||||
SEL sortSel = @selector(caseInsensitiveCompare:);
|
||||
@ -340,8 +332,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
|
||||
#pragma mark - Separating Parts
|
||||
|
||||
+ (NSArray *)MIMEPartsWithBoundary:(NSString *)boundary
|
||||
data:(NSData *)fullDocumentData {
|
||||
+ (NSArray *)MIMEPartsWithBoundary:(NSString *)boundary data:(NSData *)fullDocumentData {
|
||||
// In MIME documents, the boundary is preceded by CRLF and two dashes, and followed
|
||||
// at the end by two dashes.
|
||||
NSData *boundaryData = [boundary dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@ -367,9 +358,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
} else {
|
||||
// A no-op self invocation on fullDocumentData will keep it retained until the block is invoked.
|
||||
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dataWrapper = dispatch_data_create(fullDocumentData.bytes,
|
||||
fullDocumentData.length,
|
||||
bgQueue, ^{ [fullDocumentData self]; });
|
||||
dataWrapper = dispatch_data_create(fullDocumentData.bytes, fullDocumentData.length, bgQueue, ^{
|
||||
[fullDocumentData self];
|
||||
});
|
||||
}
|
||||
NSMutableArray *parts;
|
||||
NSInteger previousBoundaryOffset = -1;
|
||||
@ -394,15 +385,13 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
if (previousPartDataLength < 2) {
|
||||
// The preceding part was too short to be useful.
|
||||
#if DEBUG
|
||||
NSLog(@"MIME part %ld has %ld bytes", (long)partCounter - 1,
|
||||
(long)previousPartDataLength);
|
||||
NSLog(@"MIME part %ld has %ld bytes", (long)partCounter - 1, (long)previousPartDataLength);
|
||||
#endif
|
||||
} else {
|
||||
if (!parts) parts = [NSMutableArray array];
|
||||
|
||||
dispatch_data_t partData =
|
||||
dispatch_data_create_subrange(dataWrapper,
|
||||
(size_t)previousPartDataStartOffset, (size_t)previousPartDataLength);
|
||||
dispatch_data_t partData = dispatch_data_create_subrange(
|
||||
dataWrapper, (size_t)previousPartDataStartOffset, (size_t)previousPartDataLength);
|
||||
// Scan the part data for the separator between headers and body. After the CRLF,
|
||||
// either the headers start immediately, or there's another CRLF and there are no headers.
|
||||
//
|
||||
@ -412,12 +401,18 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
// and map that two-byte subrange.
|
||||
const void *partDataBuffer;
|
||||
size_t partDataBufferSize;
|
||||
// The clang included with Xcode 13.3 betas added a -Wunused-but-set-variable warning,
|
||||
// which doesn't (yet) skip variables annotated with objc_precie_lifetime. Since that
|
||||
// warning is not available in all Xcodes, turn off the -Wunused warning group entirely.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused"
|
||||
dispatch_data_t mappedPartData NS_VALID_UNTIL_END_OF_SCOPE =
|
||||
dispatch_data_create_map(partData, &partDataBuffer, &partDataBufferSize);
|
||||
#pragma clang diagnostic pop
|
||||
dispatch_data_t bodyData;
|
||||
NSDictionary *headers;
|
||||
BOOL hasAnotherCRLF = (((char *)partDataBuffer)[0] == '\r'
|
||||
&& ((char *)partDataBuffer)[1] == '\n');
|
||||
BOOL hasAnotherCRLF =
|
||||
(((char *)partDataBuffer)[0] == '\r' && ((char *)partDataBuffer)[1] == '\n');
|
||||
mappedPartData = nil;
|
||||
|
||||
if (hasAnotherCRLF) {
|
||||
@ -442,14 +437,18 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
dispatch_data_create_subrange(partData, 0, (size_t)headerSeparatorOffset);
|
||||
headers = [self headersWithData:(NSData *)headerData];
|
||||
|
||||
bodyData = dispatch_data_create_subrange(partData, (size_t)headerSeparatorOffset + 4,
|
||||
bodyData = dispatch_data_create_subrange(
|
||||
partData, (size_t)headerSeparatorOffset + 4,
|
||||
(size_t)(previousPartDataLength - (headerSeparatorOffset + 4)));
|
||||
|
||||
numberOfPartsWithHeaders++;
|
||||
} // crlfOffsets.count == 0
|
||||
} // hasAnotherCRLF
|
||||
GTMMIMEDocumentPart *part = [GTMMIMEDocumentPart partWithHeaders:headers
|
||||
body:(NSData *)bodyData];
|
||||
} // hasAnotherCRLF
|
||||
|
||||
// bodyData being nil reflects malformed data; if so provide an empty
|
||||
// NSData object rather than pass nil to a nonnull parameter.
|
||||
GTMMIMEDocumentPart *part =
|
||||
[GTMMIMEDocumentPart partWithHeaders:headers body:(NSData *)bodyData ?: [NSData data]];
|
||||
[parts addObject:part];
|
||||
} // previousPartDataLength < 2
|
||||
previousBoundaryOffset = currentBoundaryOffset.integerValue;
|
||||
@ -461,10 +460,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
NSUInteger length = fullDocumentData.length;
|
||||
if (length > 20) { // Reasonably long.
|
||||
NSMutableArray *foundCRLFs;
|
||||
[self searchData:fullDocumentData
|
||||
targetBytes:"\r\n"
|
||||
targetLength:2
|
||||
foundOffsets:&foundCRLFs];
|
||||
[self searchData:fullDocumentData targetBytes:"\r\n" targetLength:2 foundOffsets:&foundCRLFs];
|
||||
if (foundCRLFs.count == 0) {
|
||||
// Parts were logged above (due to lacking header separators.)
|
||||
NSLog(@"Warning: MIME document lacks any headers (may have wrong line endings)");
|
||||
@ -484,21 +480,20 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
+ (void)searchData:(NSData *)data
|
||||
targetBytes:(const void *)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets {
|
||||
foundOffsets:(NSArray<NSNumber *> **)outFoundOffsets {
|
||||
NSMutableArray *foundOffsets = [NSMutableArray array];
|
||||
SearchDataForBytes(data, targetBytes, targetLength, foundOffsets, NULL);
|
||||
*outFoundOffsets = foundOffsets;
|
||||
}
|
||||
|
||||
|
||||
// This version of searchData: also returns the block numbers (0-based) where the
|
||||
// target was found, used for testing that the supplied dispatch_data buffer
|
||||
// has not been flattened.
|
||||
+ (void)searchData:(NSData *)data
|
||||
targetBytes:(const void *)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets
|
||||
foundBlockNumbers:(GTM_NSArrayOf(NSNumber *) **)outFoundBlockNumbers {
|
||||
targetBytes:(const void *)targetBytes
|
||||
targetLength:(NSUInteger)targetLength
|
||||
foundOffsets:(NSArray<NSNumber *> **)outFoundOffsets
|
||||
foundBlockNumbers:(NSArray<NSNumber *> **)outFoundBlockNumbers {
|
||||
NSMutableArray *foundOffsets = [NSMutableArray array];
|
||||
NSMutableArray *foundBlockNumbers = [NSMutableArray array];
|
||||
|
||||
@ -513,9 +508,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
__block NSInteger priorPartialMatchStartingBlockNumber = -1;
|
||||
__block NSInteger blockNumber = -1;
|
||||
|
||||
[data enumerateByteRangesUsingBlock:^(const void *bytes,
|
||||
NSRange byteRange,
|
||||
BOOL *stop) {
|
||||
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
|
||||
// Search for the first character in the current range.
|
||||
const void *ptr = bytes;
|
||||
NSInteger remainingInCurrentRange = (NSInteger)byteRange.length;
|
||||
@ -524,9 +517,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
if (priorPartialMatchAmount > 0) {
|
||||
NSUInteger amountRemainingToBeMatched = targetLength - priorPartialMatchAmount;
|
||||
NSUInteger remainingFoundOffset;
|
||||
NSUInteger amountMatched = FindBytes(targetBytes + priorPartialMatchAmount,
|
||||
amountRemainingToBeMatched,
|
||||
ptr, (NSUInteger)remainingInCurrentRange, &remainingFoundOffset);
|
||||
NSUInteger amountMatched =
|
||||
FindBytes(targetBytes + priorPartialMatchAmount, amountRemainingToBeMatched, ptr,
|
||||
(NSUInteger)remainingInCurrentRange, &remainingFoundOffset);
|
||||
if (amountMatched == 0 || remainingFoundOffset > 0) {
|
||||
// No match of the rest of the prior partial match in this range.
|
||||
} else if (amountMatched < amountRemainingToBeMatched) {
|
||||
@ -589,9 +582,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
NSCharacterSet *newlineCharacters = [NSCharacterSet newlineCharacterSet];
|
||||
NSString *key;
|
||||
NSString *value;
|
||||
while ([scanner scanUpToString:@":" intoString:&key]
|
||||
&& [scanner scanString:@":" intoString:NULL]
|
||||
&& [scanner scanUpToCharactersFromSet:newlineCharacters intoString:&value]) {
|
||||
while ([scanner scanUpToString:@":" intoString:&key] &&
|
||||
[scanner scanString:@":" intoString:NULL] &&
|
||||
[scanner scanUpToCharactersFromSet:newlineCharacters intoString:&value]) {
|
||||
[headers setObject:value forKey:key];
|
||||
// Discard the trailing newline.
|
||||
[scanner scanCharactersFromSet:newlineCharacters intoString:NULL];
|
||||
@ -605,8 +598,8 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
||||
//
|
||||
// If the result is less than needleLen, then the beginning of the needle
|
||||
// was found at the end of the haystack.
|
||||
static NSUInteger FindBytes(const unsigned char* needle, NSUInteger needleLen,
|
||||
const unsigned char* haystack, NSUInteger haystackLen,
|
||||
static NSUInteger FindBytes(const unsigned char *needle, NSUInteger needleLen,
|
||||
const unsigned char *haystack, NSUInteger haystackLen,
|
||||
NSUInteger *foundOffset) {
|
||||
const unsigned char *ptr = haystack;
|
||||
NSInteger remain = (NSInteger)haystackLen;
|
||||
|
||||
@ -15,24 +15,26 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// These will be removed in the near future, folks should move off of them.
|
||||
#ifndef GTM_NONNULL
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(nonnull)
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#else
|
||||
#define GTM_NONNULL(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GTMReadMonitorInputStream : NSInputStream <NSStreamDelegate>
|
||||
|
||||
+ (instancetype)inputStreamWithStream:(NSInputStream *)input GTM_NONNULL((1));
|
||||
+ (nonnull instancetype)inputStreamWithStream:(nonnull NSInputStream *)input;
|
||||
|
||||
- (instancetype)initWithStream:(NSInputStream *)input GTM_NONNULL((1));
|
||||
- (nonnull instancetype)initWithStream:(nonnull NSInputStream *)input;
|
||||
|
||||
// The read monitor selector is called when bytes have been read. It should have this signature:
|
||||
//
|
||||
@ -41,9 +43,11 @@
|
||||
// length:(int64_t)length;
|
||||
|
||||
@property(atomic, weak) id readDelegate;
|
||||
@property(atomic, assign) SEL readSelector;
|
||||
@property(atomic) SEL readSelector;
|
||||
|
||||
// Modes for invoking callbacks, when necessary.
|
||||
@property(atomic, strong) NSArray *runLoopModes;
|
||||
@property(atomic, copy, nullable) NSArray *runLoopModes;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -20,13 +20,12 @@
|
||||
#import "GTMReadMonitorInputStream.h"
|
||||
|
||||
@implementation GTMReadMonitorInputStream {
|
||||
NSInputStream *_inputStream; // Encapsulated stream that does the work.
|
||||
NSInputStream *_inputStream; // Encapsulated stream that does the work.
|
||||
|
||||
NSThread *_thread; // Thread in which this object was created.
|
||||
NSArray *_runLoopModes; // Modes for calling callbacks, when necessary.
|
||||
NSThread *_thread; // Thread in which this object was created.
|
||||
NSArray *_runLoopModes; // Modes for calling callbacks, when necessary.
|
||||
}
|
||||
|
||||
|
||||
@synthesize readDelegate = _readDelegate;
|
||||
@synthesize readSelector = _readSelector;
|
||||
@synthesize runLoopModes = _runLoopModes;
|
||||
@ -38,7 +37,7 @@
|
||||
return [NSInputStream methodSignatureForSelector:selector];
|
||||
}
|
||||
|
||||
+ (void)forwardInvocation:(NSInvocation*)invocation {
|
||||
+ (void)forwardInvocation:(NSInvocation *)invocation {
|
||||
[invocation invokeWithTarget:[NSInputStream class]];
|
||||
}
|
||||
|
||||
@ -46,11 +45,11 @@
|
||||
return [_inputStream respondsToSelector:selector];
|
||||
}
|
||||
|
||||
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
|
||||
return [_inputStream methodSignatureForSelector:selector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation*)invocation {
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation {
|
||||
[invocation invokeWithTarget:_inputStream];
|
||||
}
|
||||
|
||||
@ -60,7 +59,7 @@
|
||||
return [[self alloc] initWithStream:input];
|
||||
}
|
||||
|
||||
- (instancetype)initWithStream:(NSInputStream *)input {
|
||||
- (instancetype)initWithStream:(NSInputStream *)input {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_inputStream = input;
|
||||
@ -103,10 +102,7 @@
|
||||
waitUntilDone:NO
|
||||
modes:_runLoopModes];
|
||||
} else {
|
||||
[self performSelector:sel
|
||||
onThread:_thread
|
||||
withObject:data
|
||||
waitUntilDone:NO];
|
||||
[self performSelector:sel onThread:_thread withObject:data waitUntilDone:NO];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
@ -155,11 +151,11 @@
|
||||
[_inputStream close];
|
||||
}
|
||||
|
||||
- (id)delegate {
|
||||
- (id<NSStreamDelegate>)delegate {
|
||||
return [_inputStream delegate];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)delegate {
|
||||
- (void)setDelegate:(id<NSStreamDelegate>)delegate {
|
||||
[_inputStream setDelegate:delegate];
|
||||
}
|
||||
|
||||
|
||||
578
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
generated
578
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
generated
@ -136,6 +136,8 @@
|
||||
// Alternative HTTP methods, like PUT, and custom headers can be specified by
|
||||
// creating the fetcher with an appropriate NSMutableURLRequest.
|
||||
//
|
||||
// Custom headers can also be provided per-request via an instance of `GTMFetcherDecoratorProtocol`
|
||||
// passed to `-[GTMSessionFetcherService addDecorator:]`.
|
||||
//
|
||||
// Caching:
|
||||
//
|
||||
@ -179,9 +181,8 @@
|
||||
// Note: cookies set while following redirects will be sent to the server, as
|
||||
// the redirects are followed by the fetcher.
|
||||
//
|
||||
// To completely disable cookies, similar to setting cookieStorageMethod to
|
||||
// kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration
|
||||
// appropriately in the fetcher or fetcher service:
|
||||
// To completely disable cookies, adjust the session configuration appropriately
|
||||
// in the fetcher or fetcher service:
|
||||
// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
|
||||
// NSURLSessionConfiguration *config) {
|
||||
// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
|
||||
@ -258,7 +259,6 @@
|
||||
// response(suggestedWillRetry);
|
||||
// };
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
@ -271,93 +271,101 @@
|
||||
// By default it is stripped from non DEBUG builds. Developers can override
|
||||
// this in their project settings.
|
||||
#ifndef STRIP_GTM_FETCH_LOGGING
|
||||
#if !DEBUG
|
||||
#define STRIP_GTM_FETCH_LOGGING 1
|
||||
#else
|
||||
#define STRIP_GTM_FETCH_LOGGING 0
|
||||
#endif
|
||||
#if !DEBUG
|
||||
#define STRIP_GTM_FETCH_LOGGING 1
|
||||
#else
|
||||
#define STRIP_GTM_FETCH_LOGGING 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Logs in debug builds.
|
||||
#ifndef GTMSESSION_LOG_DEBUG
|
||||
#if DEBUG
|
||||
#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
|
||||
#else
|
||||
#define GTMSESSION_LOG_DEBUG(...) do { } while (0)
|
||||
#endif
|
||||
#if DEBUG
|
||||
#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
|
||||
#else
|
||||
#define GTMSESSION_LOG_DEBUG(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG
|
||||
// or NS_BLOCK_ASSERTIONS are defined.)
|
||||
#ifndef GTMSESSION_ASSERT_DEBUG
|
||||
#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
|
||||
#undef GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_AS_LOG 1
|
||||
#endif
|
||||
#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
|
||||
#undef GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_AS_LOG 1
|
||||
#endif
|
||||
|
||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
|
||||
#elif DEBUG
|
||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
|
||||
#else
|
||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0)
|
||||
#endif
|
||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
|
||||
#elif DEBUG
|
||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) \
|
||||
if (!(pred)) { \
|
||||
NSLog(__VA_ARGS__); \
|
||||
}
|
||||
#else
|
||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Asserts in debug builds, logs in release builds (or logs in debug builds if
|
||||
// GTMSESSION_ASSERT_AS_LOG is defined.)
|
||||
#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG
|
||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__)
|
||||
#else
|
||||
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Macro useful for examining messages from NSURLSession during debugging.
|
||||
#if 0
|
||||
#define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__)
|
||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__)
|
||||
#else
|
||||
#define GTM_LOG_SESSION_DELEGATE(...)
|
||||
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) \
|
||||
if (!(pred)) { \
|
||||
NSLog(__VA_ARGS__); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Macro useful for more verbose logging from NSURLSession during debugging.
|
||||
#if 0
|
||||
#define GTMSESSION_LOG_DEBUG_VERBOSE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__)
|
||||
#else
|
||||
#define GTMSESSION_LOG_DEBUG_VERBOSE(...)
|
||||
#endif
|
||||
|
||||
// These will be removed in the near future, folks should move off of them.
|
||||
#ifndef GTM_NULLABLE
|
||||
#if __has_feature(nullability) // Available starting in Xcode 6.3
|
||||
#define GTM_NULLABLE_TYPE __nullable
|
||||
#define GTM_NONNULL_TYPE __nonnull
|
||||
#define GTM_NULLABLE nullable
|
||||
#define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
|
||||
#define GTM_NULL_RESETTABLE null_resettable
|
||||
|
||||
#define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
|
||||
#define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
|
||||
#else
|
||||
#define GTM_NULLABLE_TYPE
|
||||
#define GTM_NONNULL_TYPE
|
||||
#define GTM_NULLABLE
|
||||
#define GTM_NONNULL_DECL
|
||||
#define GTM_NULL_RESETTABLE
|
||||
#define GTM_ASSUME_NONNULL_BEGIN
|
||||
#define GTM_ASSUME_NONNULL_END
|
||||
#endif // __has_feature(nullability)
|
||||
#if __has_feature(nullability) // Available starting in Xcode 6.3
|
||||
#define GTM_NULLABLE_TYPE __nullable
|
||||
#define GTM_NONNULL_TYPE __nonnull
|
||||
#define GTM_NULLABLE nullable
|
||||
#define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
|
||||
#define GTM_NULL_RESETTABLE null_resettable
|
||||
#define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
|
||||
#define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
|
||||
#else
|
||||
#define GTM_NULLABLE_TYPE
|
||||
#define GTM_NONNULL_TYPE
|
||||
#define GTM_NULLABLE
|
||||
#define GTM_NONNULL_DECL
|
||||
#define GTM_NULL_RESETTABLE
|
||||
#define GTM_ASSUME_NONNULL_BEGIN
|
||||
#define GTM_ASSUME_NONNULL_END
|
||||
#endif // __has_feature(nullability)
|
||||
#endif // GTM_NULLABLE
|
||||
|
||||
#ifndef GTM_DECLARE_GENERICS
|
||||
#if __has_feature(objc_generics)
|
||||
#define GTM_DECLARE_GENERICS 1
|
||||
#else
|
||||
#define GTM_DECLARE_GENERICS 0
|
||||
#endif
|
||||
#if __has_feature(objc_generics)
|
||||
#define GTM_DECLARE_GENERICS 1
|
||||
#else
|
||||
#define GTM_DECLARE_GENERICS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GTM_NSArrayOf
|
||||
#if GTM_DECLARE_GENERICS
|
||||
#define GTM_NSArrayOf(value) NSArray<value>
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||
#else
|
||||
#define GTM_NSArrayOf(value) NSArray
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||
#endif // __has_feature(objc_generics)
|
||||
#if GTM_DECLARE_GENERICS
|
||||
#define GTM_NSArrayOf(value) NSArray<value>
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||
#else
|
||||
#define GTM_NSArrayOf(value) NSArray
|
||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||
#endif // __has_feature(objc_generics)
|
||||
#endif // GTM_NSArrayOf
|
||||
|
||||
// For iOS, the fetcher can declare itself a background task to allow fetches
|
||||
@ -369,50 +377,28 @@
|
||||
// To disallow use of background tasks during fetches, the target should define
|
||||
// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the
|
||||
// skipBackgroundTask property to YES.
|
||||
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING)
|
||||
#define GTM_BACKGROUND_TASK_FETCHING 1
|
||||
#if !defined(GTM_BACKGROUND_TASK_FETCHING) && \
|
||||
(TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST)
|
||||
#define GTM_BACKGROUND_TASK_FETCHING 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (TARGET_OS_TV \
|
||||
|| TARGET_OS_WATCH \
|
||||
|| (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \
|
||||
|| (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0))
|
||||
#ifndef GTM_USE_SESSION_FETCHER
|
||||
#define GTM_USE_SESSION_FETCHER 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(GTMBridgeFetcher)
|
||||
// These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h
|
||||
#if GTM_USE_SESSION_FETCHER
|
||||
// Macros to new fetcher class.
|
||||
#define GTMBridgeFetcher GTMSessionFetcher
|
||||
#define GTMBridgeFetcherService GTMSessionFetcherService
|
||||
#define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
|
||||
#define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
|
||||
#define GTMBridgeCookieStorage GTMSessionCookieStorage
|
||||
#define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
|
||||
#define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
|
||||
#define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
|
||||
#define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
|
||||
#define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest
|
||||
#else
|
||||
// Macros to old fetcher class.
|
||||
#define GTMBridgeFetcher GTMHTTPFetcher
|
||||
#define GTMBridgeFetcherService GTMHTTPFetcherService
|
||||
#define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol
|
||||
#define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs
|
||||
#define GTMBridgeCookieStorage GTMCookieStorage
|
||||
#define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString
|
||||
#define GTMBridgeSystemVersionString GTMSystemVersionString
|
||||
#define GTMBridgeApplicationIdentifier GTMApplicationIdentifier
|
||||
#define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain
|
||||
#define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest
|
||||
#endif // GTM_USE_SESSION_FETCHER
|
||||
// The bridge macros are deprecated, and should be replaced; GTMHTTPFetcher is no longer
|
||||
// supported and all code should switch to use GTMSessionFetcher types directly.
|
||||
#define GTMBridgeFetcher GTMSessionFetcher
|
||||
#define GTMBridgeFetcherService GTMSessionFetcherService
|
||||
#define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
|
||||
#define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
|
||||
#define GTMBridgeCookieStorage GTMSessionCookieStorage
|
||||
#define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
|
||||
#define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
|
||||
#define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
|
||||
#define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
|
||||
#define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest
|
||||
#endif
|
||||
|
||||
// When creating background sessions to perform out-of-process uploads and
|
||||
@ -433,15 +419,15 @@ extern "C" {
|
||||
// Apps targeting new SDKs can force the old behavior by defining
|
||||
// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0.
|
||||
#ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
|
||||
// Default to the on-launch behavior for iOS 13+.
|
||||
#if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
|
||||
#else
|
||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
|
||||
#endif
|
||||
// Default to the on-launch behavior for iOS 13+.
|
||||
#if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
|
||||
#else
|
||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
GTM_ASSUME_NONNULL_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// Notifications
|
||||
//
|
||||
@ -523,24 +509,26 @@ extern "C" {
|
||||
typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
|
||||
NSURLSessionConfiguration *configuration);
|
||||
typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
|
||||
typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data,
|
||||
NSError * GTM_NULLABLE_TYPE error);
|
||||
typedef void (^GTMSessionFetcherCompletionHandler)(NSData *_Nullable data,
|
||||
NSError *_Nullable error);
|
||||
typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
|
||||
typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response);
|
||||
typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition);
|
||||
typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response,
|
||||
GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
|
||||
typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition,
|
||||
NSURLCredential * GTM_NULLABLE_TYPE credential);
|
||||
typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher,
|
||||
NSURLAuthenticationChallenge *challenge,
|
||||
GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
|
||||
typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest);
|
||||
typedef void (^GTMSessionFetcherBodyStreamProvider)(
|
||||
GTMSessionFetcherBodyStreamProviderResponse response);
|
||||
typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(
|
||||
NSURLSessionResponseDisposition disposition);
|
||||
typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(
|
||||
NSURLResponse *response, GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
|
||||
typedef void (^GTMSessionFetcherChallengeDispositionBlock)(
|
||||
NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *_Nullable credential);
|
||||
typedef void (^GTMSessionFetcherChallengeBlock)(
|
||||
GTMSessionFetcher *fetcher, NSURLAuthenticationChallenge *challenge,
|
||||
GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
|
||||
typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest *_Nullable redirectedRequest);
|
||||
typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse,
|
||||
NSURLRequest *redirectRequest,
|
||||
GTMSessionFetcherWillRedirectResponse response);
|
||||
typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer);
|
||||
typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer,
|
||||
typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData *_Nullable buffer);
|
||||
typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData *_Nullable buffer,
|
||||
int64_t bytesWritten,
|
||||
int64_t totalBytesWritten,
|
||||
int64_t totalBytesExpectedToWrite);
|
||||
@ -549,27 +537,26 @@ typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten,
|
||||
typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten,
|
||||
int64_t totalBytesWritten,
|
||||
int64_t totalBytesExpectedToWrite);
|
||||
typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent,
|
||||
int64_t totalBytesSent,
|
||||
typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, int64_t totalBytesSent,
|
||||
int64_t totalBytesExpectedToSend);
|
||||
typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse);
|
||||
typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse,
|
||||
GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
|
||||
typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(
|
||||
NSCachedURLResponse *_Nullable cachedResponse);
|
||||
typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(
|
||||
NSCachedURLResponse *proposedResponse,
|
||||
GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
|
||||
typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry);
|
||||
typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry,
|
||||
NSError * GTM_NULLABLE_TYPE error,
|
||||
typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, NSError *_Nullable error,
|
||||
GTMSessionFetcherRetryResponse response);
|
||||
|
||||
API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0))
|
||||
API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0))
|
||||
typedef void (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics);
|
||||
|
||||
typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response,
|
||||
NSData * GTM_NULLABLE_TYPE data,
|
||||
NSError * GTM_NULLABLE_TYPE error);
|
||||
typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse *_Nullable response,
|
||||
NSData *_Nullable data, NSError *_Nullable error);
|
||||
typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest,
|
||||
GTMSessionFetcherTestResponse testResponse);
|
||||
|
||||
void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...);
|
||||
void GTMSessionFetcherAssertValidSelector(id _Nullable obj, SEL _Nullable sel, ...);
|
||||
|
||||
// Utility functions for applications self-identifying to servers via a
|
||||
// user-agent header
|
||||
@ -581,7 +568,7 @@ void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULL
|
||||
// Applications may use this as a starting point for their own user agent strings, perhaps
|
||||
// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to
|
||||
// clean up any string being added to the user agent.
|
||||
NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle);
|
||||
NSString *GTMFetcherStandardUserAgentString(NSBundle *_Nullable bundle);
|
||||
|
||||
// Make a generic name and version for the current application, like
|
||||
// com.example.MyApp/1.2.3 relying on the bundle identifier and the
|
||||
@ -590,9 +577,12 @@ NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle)
|
||||
// The bundle ID may be overridden as the base identifier string by
|
||||
// adding to the bundle's Info.plist a "GTMUserAgentID" key.
|
||||
//
|
||||
// The application version may be overridden by adding to the bundle's
|
||||
// Info.plist a "GTMUserAgentVersion" key.
|
||||
//
|
||||
// If no bundle ID or override is available, the process name preceded
|
||||
// by "proc_" is used.
|
||||
NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle);
|
||||
NSString *GTMFetcherApplicationIdentifier(NSBundle *_Nullable bundle);
|
||||
|
||||
// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1"
|
||||
NSString *GTMFetcherSystemVersionString(void);
|
||||
@ -615,16 +605,60 @@ NSString *GTMFetcherCleanedUserAgentString(NSString *str);
|
||||
// queue before calling this function.
|
||||
//
|
||||
// Failure is indicated by a returned data value of nil.
|
||||
NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError);
|
||||
NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// Completion handler passed to -[GTMFetcherDecoratorProtocol fetcherWillStart:completionHandler:].
|
||||
typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLRequest *_Nullable,
|
||||
NSError *_Nullable);
|
||||
|
||||
#if !GTM_USE_SESSION_FETCHER
|
||||
@protocol GTMHTTPFetcherServiceProtocol;
|
||||
#endif
|
||||
// Allows intercepting a request and optionally modifying it before the request (or a retry)
|
||||
// is sent. See `-[GTMSessionFetcherService addDecorator:]` and `-[GTMSessionFetcherService
|
||||
// removeDecorator:]`.
|
||||
//
|
||||
// Decorator methods must be thread-safe, as they might be invoked on any queue.
|
||||
@protocol GTMFetcherDecoratorProtocol <NSObject>
|
||||
|
||||
// Invoked just before a fetcher's request starts.
|
||||
//
|
||||
// After the decorator's work is complete, the decorator must invoke `handler(request, error)`
|
||||
// either synchronously or asynchronously (on any queue).
|
||||
//
|
||||
// If no changes are to be made, pass `nil` for both `request` and `error`.
|
||||
//
|
||||
// Otherwise, if `error` is non-nil, then the fetcher is stopped with the given error, and any
|
||||
// further decorators' `-fetcherWillStart:completionHandler:` methods are not invoked.
|
||||
//
|
||||
// Otherwise, the decorator may use `[fetcher.request mutableCopy]`, make changes to the mutable
|
||||
// copy of the request, and pass the result to the handler via the `request` parameter.
|
||||
//
|
||||
// To distinguish the initial fetch from retries, the decorator can look at `fetcher.retryCount`.
|
||||
//
|
||||
// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking
|
||||
// work or I/O on a different queue, then invoke `handler` with the results after the blocking work
|
||||
// completes.
|
||||
- (void)fetcherWillStart:(GTMSessionFetcher *)fetcher
|
||||
completionHandler:(GTMFetcherDecoratorFetcherWillStartCompletionHandler)handler;
|
||||
|
||||
// Invoked just after a fetcher's request finishes (either on success or on failure).
|
||||
//
|
||||
// After the decorator's work is complete, the decorator must invoke `handler()` either
|
||||
// synchronously or asynchronously (on any queue).
|
||||
//
|
||||
// To access the result of the fetch, the decorator can look at `fetcher.response`.
|
||||
//
|
||||
// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking
|
||||
// work or I/O on a different queue, then invoke `handler` with the results after the blocking work
|
||||
// completes.
|
||||
- (void)fetcherDidFinish:(GTMSessionFetcher *)fetcher
|
||||
withData:(nullable NSData *)data
|
||||
error:(nullable NSError *)error
|
||||
completionHandler:(void (^)(void))handler;
|
||||
|
||||
@end
|
||||
|
||||
// This protocol allows abstract references to the fetcher service, primarily for
|
||||
// fetchers (which may be compiled without the fetcher service class present.)
|
||||
@ -645,13 +679,17 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
|
||||
|
||||
@property(atomic, assign) BOOL reuseSession;
|
||||
- (GTM_NULLABLE NSURLSession *)session;
|
||||
- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
|
||||
- (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
|
||||
- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
|
||||
- (nullable NSURLSession *)session;
|
||||
- (nullable NSURLSession *)sessionForFetcherCreation;
|
||||
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
|
||||
- (nullable NSDate *)stoppedAllFetchersDate;
|
||||
|
||||
// Methods for compatibility with the old GTMHTTPFetcher.
|
||||
@property(atomic, readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue;
|
||||
@property(atomic, readonly, strong, nullable) NSOperationQueue *delegateQueue;
|
||||
|
||||
@optional
|
||||
// This property is optional, for now, to enable releasing the feature without breaking existing
|
||||
// code that fakes the service but doesn't implement this.
|
||||
@property(atomic, readonly, strong, nullable) NSArray<id<GTMFetcherDecoratorProtocol>> *decorators;
|
||||
|
||||
@end // @protocol GTMSessionFetcherServiceProtocol
|
||||
|
||||
@ -661,7 +699,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
@required
|
||||
// This protocol allows us to call the authorizer without requiring its sources
|
||||
// in this project.
|
||||
- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
|
||||
- (void)authorizeRequest:(nullable NSMutableURLRequest *)request
|
||||
delegate:(id)delegate
|
||||
didFinishSelector:(SEL)sel;
|
||||
|
||||
@ -673,7 +711,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
|
||||
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
||||
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) NSString *userEmail;
|
||||
@property(atomic, strong, readonly, nullable) NSString *userEmail;
|
||||
|
||||
@optional
|
||||
|
||||
@ -685,14 +723,10 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// transmission of the bearer token unencrypted.
|
||||
@property(atomic, assign) BOOL shouldAuthorizeAllRequests;
|
||||
|
||||
- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
|
||||
completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler;
|
||||
- (void)authorizeRequest:(nullable NSMutableURLRequest *)request
|
||||
completionHandler:(void (^)(NSError *_Nullable error))handler;
|
||||
|
||||
#if GTM_USE_SESSION_FETCHER
|
||||
@property(atomic, weak, GTM_NULLABLE) id<GTMSessionFetcherServiceProtocol> fetcherService;
|
||||
#else
|
||||
@property(atomic, weak, GTM_NULLABLE) id<GTMHTTPFetcherServiceProtocol> fetcherService;
|
||||
#endif
|
||||
@property(atomic, weak, nullable) id<GTMSessionFetcherServiceProtocol> fetcherService;
|
||||
|
||||
- (BOOL)primeForRefresh;
|
||||
|
||||
@ -704,7 +738,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:]
|
||||
@protocol GTMUIApplicationProtocol <NSObject>
|
||||
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName
|
||||
expirationHandler:(void(^ __nullable)(void))handler;
|
||||
expirationHandler:(void (^__nullable)(void))handler;
|
||||
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
|
||||
@end
|
||||
#endif
|
||||
@ -722,7 +756,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// the connection is successfully created, the connection should retain the
|
||||
// fetcher for the life of the connection as well. So the caller doesn't have
|
||||
// to retain the fetcher explicitly unless they want to be able to cancel it.
|
||||
+ (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request;
|
||||
+ (instancetype)fetcherWithRequest:(nullable NSURLRequest *)request;
|
||||
|
||||
// Convenience methods that make a request, like +fetcherWithRequest
|
||||
+ (instancetype)fetcherWithURL:(NSURL *)requestURL;
|
||||
@ -730,11 +764,11 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
|
||||
// Methods for creating fetchers to continue previous fetches.
|
||||
+ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData;
|
||||
+ (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier;
|
||||
+ (nullable instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier;
|
||||
|
||||
// Returns an array of currently active fetchers for background sessions,
|
||||
// both restarted and newly created ones.
|
||||
+ (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions;
|
||||
+ (NSArray<GTMSessionFetcher *> *)fetchersForBackgroundSessions;
|
||||
|
||||
// Designated initializer.
|
||||
//
|
||||
@ -743,19 +777,19 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
//
|
||||
// The configuration should typically be nil. Applications needing to customize
|
||||
// the configuration may do so by setting the configurationBlock property.
|
||||
- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request
|
||||
configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration;
|
||||
- (instancetype)initWithRequest:(nullable NSURLRequest *)request
|
||||
configuration:(nullable NSURLSessionConfiguration *)configuration;
|
||||
|
||||
// The fetcher's request. This may not be set after beginFetch has been invoked. The request
|
||||
// may change due to redirects.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLRequest *request;
|
||||
@property(atomic, strong, nullable) NSURLRequest *request;
|
||||
|
||||
// Set a header field value on the request. Header field value changes will not
|
||||
// affect a fetch after the fetch has begun.
|
||||
- (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field;
|
||||
- (void)setRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;
|
||||
|
||||
// Data used for resuming a download task.
|
||||
@property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData;
|
||||
@property(atomic, readonly, nullable) NSData *downloadResumeData;
|
||||
|
||||
// The configuration; this must be set before the fetch begins. If no configuration is
|
||||
// set or inherited from the fetcher service, then the fetcher uses an ephemeral config.
|
||||
@ -764,7 +798,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// the configuration should do so by setting the configurationBlock property.
|
||||
// That allows the fetcher to pick an appropriate base configuration, with the
|
||||
// application setting only the configuration properties it needs to customize.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration;
|
||||
@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration;
|
||||
|
||||
// A block the client may use to customize the configuration used to create the session.
|
||||
//
|
||||
@ -776,17 +810,17 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// DO NOT change any fetcher properties in the configuration block. Fetcher properties
|
||||
// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior
|
||||
// to invoking beginFetch.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock;
|
||||
|
||||
// A session is created as needed by the fetcher. A fetcher service object
|
||||
// may maintain sessions for multiple fetches to the same host.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLSession *session;
|
||||
@property(atomic, strong, nullable) NSURLSession *session;
|
||||
|
||||
// The task in flight.
|
||||
@property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask;
|
||||
@property(atomic, readonly, nullable) NSURLSessionTask *sessionTask;
|
||||
|
||||
// The background session identifier.
|
||||
@property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier;
|
||||
@property(atomic, readonly, nullable) NSString *sessionIdentifier;
|
||||
|
||||
// Indicates a fetcher created to finish a background session task.
|
||||
@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession;
|
||||
@ -800,10 +834,10 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// Additional user-supplied data to encode into the session identifier. Since session identifier
|
||||
// length limits are unspecified, this should be kept small. Key names beginning with an underscore
|
||||
// are reserved for use by the fetcher.
|
||||
@property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo;
|
||||
@property(atomic, strong, nullable) NSDictionary<NSString *, NSString *> *sessionUserInfo;
|
||||
|
||||
// The human-readable description to be assigned to the task.
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *taskDescription;
|
||||
@property(atomic, copy, nullable) NSString *taskDescription;
|
||||
|
||||
// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow,
|
||||
// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh.
|
||||
@ -812,7 +846,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// The fetcher encodes information used to resume a session in the session identifier.
|
||||
// This method, intended for internal use returns the encoded information. The sessionUserInfo
|
||||
// dictionary is stored as identifier metadata.
|
||||
- (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata;
|
||||
- (nullable NSDictionary<NSString *, NSString *> *)sessionIdentifierMetadata;
|
||||
|
||||
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
|
||||
// The app should pass to this method the completion handler passed in the app delegate method
|
||||
@ -870,7 +904,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
//
|
||||
// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when
|
||||
// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes;
|
||||
@property(atomic, copy, nullable) NSArray<NSString *> *allowedInsecureSchemes;
|
||||
|
||||
// By default, the fetcher prohibits localhost requests unless this property is set,
|
||||
// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set.
|
||||
@ -893,40 +927,40 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually
|
||||
// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage,
|
||||
// to hold cookies in memory.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage;
|
||||
@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage;
|
||||
|
||||
// Setting the credential is optional; it is used if the connection receives
|
||||
// an authentication challenge.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential;
|
||||
@property(atomic, strong, nullable) NSURLCredential *credential;
|
||||
|
||||
// Setting the proxy credential is optional; it is used if the connection
|
||||
// receives an authentication challenge from a proxy.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential;
|
||||
@property(atomic, strong, nullable) NSURLCredential *proxyCredential;
|
||||
|
||||
// If body data, body file URL, or body stream provider is not set, then a GET request
|
||||
// method is assumed.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSData *bodyData;
|
||||
@property(atomic, strong, nullable) NSData *bodyData;
|
||||
|
||||
// File to use as the request body. This forces use of an upload task.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL;
|
||||
@property(atomic, strong, nullable) NSURL *bodyFileURL;
|
||||
|
||||
// Length of body to send, expected or actual.
|
||||
@property(atomic, readonly) int64_t bodyLength;
|
||||
|
||||
// The body stream provider may be called repeatedly to provide a body.
|
||||
// Setting a body stream provider forces use of an upload task.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherBodyStreamProvider bodyStreamProvider;
|
||||
|
||||
// Object to add authorization to the request, if needed.
|
||||
//
|
||||
// This may not be changed once beginFetch has been invoked.
|
||||
@property(atomic, strong, GTM_NULLABLE) id<GTMFetcherAuthorizationProtocol> authorizer;
|
||||
@property(atomic, strong, nullable) id<GTMFetcherAuthorizationProtocol> authorizer;
|
||||
|
||||
// The service object that created and monitors this fetcher, if any.
|
||||
@property(atomic, strong) id<GTMSessionFetcherServiceProtocol> service;
|
||||
|
||||
// The host, if any, used to classify this fetcher in the fetcher service.
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *serviceHost;
|
||||
@property(atomic, copy, nullable) NSString *serviceHost;
|
||||
|
||||
// The priority, if any, used for starting fetchers in the fetcher service.
|
||||
//
|
||||
@ -941,7 +975,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// the session task response.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock;
|
||||
|
||||
// The delegate's optional challenge block may be used to inspect or alter
|
||||
// the session task challenge.
|
||||
@ -954,18 +988,18 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// challenge.previousFailureCount to identify repeated invocations.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock;
|
||||
|
||||
// The delegate's optional willRedirect block may be used to inspect or alter
|
||||
// the redirection.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherWillRedirectBlock willRedirectBlock;
|
||||
|
||||
// The optional send progress block reports body bytes uploaded.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherSendProgressBlock sendProgressBlock;
|
||||
|
||||
// The optional accumulate block may be set by clients wishing to accumulate data
|
||||
// themselves rather than let the fetcher append each buffer to an NSData.
|
||||
@ -974,25 +1008,26 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// should empty its accumulation buffer.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock;
|
||||
|
||||
// The optional received progress block may be used to monitor data
|
||||
// received from a data task.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock;
|
||||
|
||||
// The delegate's optional downloadProgress block may be used to monitor download
|
||||
// progress in writing to disk.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock;
|
||||
|
||||
// The delegate's optional willCacheURLResponse block may be used to alter the cached
|
||||
// NSURLResponse. The user may prevent caching by passing nil to the block's response.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock;
|
||||
@property(atomic, copy, nullable)
|
||||
GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock;
|
||||
|
||||
// Enable retrying; see comments at the top of this file. Setting
|
||||
// retryEnabled=YES resets the min and max retry intervals.
|
||||
@ -1003,14 +1038,14 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// If present, this block should call the response block with YES to cause a retry or NO to end the
|
||||
// fetch.
|
||||
// See comments at the top of this file.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock;
|
||||
|
||||
// The optional block for collecting the metrics of the present session.
|
||||
//
|
||||
// This is called on the callback queue.
|
||||
@property(atomic, copy, GTM_NULLABLE)
|
||||
@property(atomic, copy, nullable)
|
||||
GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
|
||||
ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0));
|
||||
ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0));
|
||||
|
||||
// Retry intervals must be strictly less than maxRetryInterval, else
|
||||
// they will be limited to maxRetryInterval and no further retries will
|
||||
@ -1061,10 +1096,9 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// If the application has specified a destinationFileURL or an accumulateDataBlock
|
||||
// for the fetcher, the data parameter passed to the callback will be nil.
|
||||
|
||||
- (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate
|
||||
didFinishSelector:(GTM_NULLABLE SEL)finishedSEL;
|
||||
- (void)beginFetchWithDelegate:(nullable id)delegate didFinishSelector:(nullable SEL)finishedSEL;
|
||||
|
||||
- (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler;
|
||||
- (void)beginFetchWithCompletionHandler:(nullable GTMSessionFetcherCompletionHandler)handler;
|
||||
|
||||
// Returns YES if this fetcher is in the process of fetching a URL.
|
||||
@property(atomic, readonly, getter=isFetching) BOOL fetching;
|
||||
@ -1074,57 +1108,61 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
- (void)stopFetching;
|
||||
|
||||
// A block to be called when the fetch completes.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherCompletionHandler completionHandler;
|
||||
|
||||
// A block to be called if download resume data becomes available.
|
||||
@property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *);
|
||||
@property(atomic, strong, nullable) void (^resumeDataBlock)(NSData *);
|
||||
|
||||
// Return the status code from the server response.
|
||||
@property(atomic, readonly) NSInteger statusCode;
|
||||
|
||||
// Return the http headers from the response.
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders;
|
||||
@property(atomic, strong, readonly, nullable) NSDictionary<NSString *, NSString *> *responseHeaders;
|
||||
|
||||
// The response, once it's been received.
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response;
|
||||
@property(atomic, strong, readonly, nullable) NSURLResponse *response;
|
||||
|
||||
// Bytes downloaded so far.
|
||||
@property(atomic, readonly) int64_t downloadedLength;
|
||||
|
||||
// Buffer of currently-downloaded data, if available.
|
||||
@property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData;
|
||||
@property(atomic, readonly, strong, nullable) NSData *downloadedData;
|
||||
|
||||
// Local path to which the downloaded file will be moved.
|
||||
//
|
||||
// If a file already exists at the path, it will be overwritten.
|
||||
// Will create the enclosing folders if they are not present.
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL;
|
||||
@property(atomic, strong, nullable) NSURL *destinationFileURL;
|
||||
|
||||
// The time this fetcher originally began fetching. This is useful as a time
|
||||
// barrier for ignoring irrelevant fetch notifications or callbacks.
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate;
|
||||
@property(atomic, strong, readonly, nullable) NSDate *initialBeginFetchDate;
|
||||
|
||||
// userData is retained solely for the convenience of the client.
|
||||
@property(atomic, strong, GTM_NULLABLE) id userData;
|
||||
@property(atomic, strong, nullable) id userData;
|
||||
|
||||
// Stored property values are retained solely for the convenience of the client.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties;
|
||||
@property(atomic, copy, nullable) NSDictionary<NSString *, id> *properties;
|
||||
|
||||
- (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property.
|
||||
- (GTM_NULLABLE id)propertyForKey:(NSString *)key;
|
||||
- (void)setProperty:(nullable id)obj
|
||||
forKey:(NSString *)key; // Pass nil for obj to remove the property.
|
||||
- (nullable id)propertyForKey:(NSString *)key;
|
||||
|
||||
- (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict;
|
||||
- (void)addPropertiesFromDictionary:(NSDictionary<NSString *, id> *)dict;
|
||||
|
||||
// Comments are useful for logging, so are strongly recommended for each fetcher.
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *comment;
|
||||
@property(atomic, copy, nullable) NSString *comment;
|
||||
|
||||
- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
|
||||
// Log of request and response, if logging is enabled
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *log;
|
||||
@property(atomic, copy, nullable) NSString *log;
|
||||
|
||||
// Callbacks are run on this queue. If none is supplied, the main queue is used.
|
||||
@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue;
|
||||
// Callbacks are run on this queue. If none is supplied, the main queue is used.
|
||||
//
|
||||
// CAUTION: This block MUST be a serial queue. Setting a concurrent queue can result in callbacks
|
||||
// being dispatched concurrently, leading events to appear out-of-order.
|
||||
@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue;
|
||||
|
||||
// The queue used internally by the session to invoke its delegate methods in the fetcher.
|
||||
//
|
||||
@ -1136,8 +1174,10 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// This value is ignored after the session has been created, so this
|
||||
// property should be set in the fetcher service rather in the fetcher as it applies
|
||||
// to a shared session.
|
||||
@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue;
|
||||
@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue;
|
||||
|
||||
// DEPRECATED: Callers should use XCTestExpectation instead.
|
||||
//
|
||||
// Spin the run loop or sleep the thread, discarding events, until the fetch has completed.
|
||||
//
|
||||
// This is only for use in testing or in tools without a user interface.
|
||||
@ -1146,7 +1186,8 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// sufficient reason for rejection from the app store.
|
||||
//
|
||||
// Returns NO if timed out.
|
||||
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
||||
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds
|
||||
__deprecated_msg("Use XCTestExpectation instead");
|
||||
|
||||
// Test block is optional for testing.
|
||||
//
|
||||
@ -1162,9 +1203,9 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// should proceed.
|
||||
//
|
||||
// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock;
|
||||
|
||||
+ (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block;
|
||||
+ (void)setGlobalTestBlock:(nullable GTMSessionFetcherTestBlock)block;
|
||||
|
||||
// When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to
|
||||
// divide the response data into if the client has streaming enabled. The data will be divided up to
|
||||
@ -1204,25 +1245,26 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// fetcher.deferResponseBodyLogging = NO;
|
||||
// }];
|
||||
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody;
|
||||
@property(atomic, copy, nullable) NSString *logRequestBody;
|
||||
@property(atomic, assign) BOOL deferResponseBodyLogging;
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody;
|
||||
@property(atomic, copy, nullable) NSString *logResponseBody;
|
||||
|
||||
// Internal logging support.
|
||||
@property(atomic, readonly) NSData *loggedStreamData;
|
||||
@property(atomic, assign) BOOL hasLoggedError;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL;
|
||||
@property(atomic, strong, nullable) NSURL *redirectedFromURL;
|
||||
- (void)appendLoggedStreamData:(NSData *)dataToAdd;
|
||||
- (void)clearLoggedStreamData;
|
||||
|
||||
#endif // STRIP_GTM_FETCH_LOGGING
|
||||
#endif // STRIP_GTM_FETCH_LOGGING
|
||||
|
||||
@end
|
||||
|
||||
@interface GTMSessionFetcher (BackwardsCompatibilityOnly)
|
||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
|
||||
// This method is just for compatibility with the old GTMHTTPFetcher class.
|
||||
- (void)setCookieStorageMethod:(NSInteger)method;
|
||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves;
|
||||
// this method is deprecated and will be removed soon.
|
||||
- (void)setCookieStorageMethod:(NSInteger)method
|
||||
__deprecated_msg("Create an NSHTTPCookieStorage and set .cookieStorage directly.");
|
||||
@end
|
||||
|
||||
// Until we can just instantiate NSHTTPCookieStorage for local use, we'll
|
||||
@ -1235,7 +1277,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
|
||||
// Add the array off cookies to the storage, replacing duplicates.
|
||||
// Also removes expired cookies from the storage.
|
||||
- (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies;
|
||||
- (void)setCookies:(nullable NSArray<NSHTTPCookie *> *)cookies;
|
||||
|
||||
- (void)removeAllCookies;
|
||||
|
||||
@ -1277,41 +1319,40 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
// Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not
|
||||
// defined or asserts are being logged instead.
|
||||
#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG)
|
||||
#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \
|
||||
varname ## counter
|
||||
#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
|
||||
__GTMSessionMonitorSynchronizedVariableInner(varname, counter)
|
||||
#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) varname##counter
|
||||
#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
|
||||
__GTMSessionMonitorSynchronizedVariableInner(varname, counter)
|
||||
|
||||
#define GTMSessionMonitorSynchronized(obj) \
|
||||
NS_VALID_UNTIL_END_OF_SCOPE id \
|
||||
__GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||
allowRecursive:NO \
|
||||
functionName:__func__]
|
||||
#define GTMSessionMonitorSynchronized(obj) \
|
||||
NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||
allowRecursive:NO \
|
||||
functionName:__func__]
|
||||
|
||||
#define GTMSessionMonitorRecursiveSynchronized(obj) \
|
||||
NS_VALID_UNTIL_END_OF_SCOPE id \
|
||||
__GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||
allowRecursive:YES \
|
||||
functionName:__func__]
|
||||
#define GTMSessionMonitorRecursiveSynchronized(obj) \
|
||||
NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||
allowRecursive:YES \
|
||||
functionName:__func__]
|
||||
|
||||
#define GTMSessionCheckSynchronized(obj) { \
|
||||
GTMSESSION_ASSERT_DEBUG( \
|
||||
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
@"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
|
||||
@" on " #obj " in %s. Call stack:\n%@", \
|
||||
__func__, [NSThread callStackSymbols]); \
|
||||
}
|
||||
#define GTMSessionCheckSynchronized(obj) \
|
||||
{ \
|
||||
GTMSESSION_ASSERT_DEBUG( \
|
||||
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
@"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
|
||||
@" on " #obj " in %s. Call stack:\n%@", \
|
||||
__func__, [NSThread callStackSymbols]); \
|
||||
}
|
||||
|
||||
#define GTMSessionCheckNotSynchronized(obj) { \
|
||||
GTMSESSION_ASSERT_DEBUG( \
|
||||
![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
@"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
|
||||
@" on " #obj " in %s by %@. Call stack:\n%@", __func__, \
|
||||
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
[NSThread callStackSymbols]); \
|
||||
}
|
||||
#define GTMSessionCheckNotSynchronized(obj) \
|
||||
{ \
|
||||
GTMSESSION_ASSERT_DEBUG( \
|
||||
![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
@"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
|
||||
@" on " #obj " in %s by %@. Call stack:\n%@", \
|
||||
__func__, [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||
[NSThread callStackSymbols]); \
|
||||
}
|
||||
|
||||
// GTMSessionSyncMonitorInternal is a private class that keeps track of the
|
||||
// beginning and end of synchronized scopes.
|
||||
@ -1323,16 +1364,23 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
||||
allowRecursive:(BOOL)allowRecursive
|
||||
functionName:(const char *)functionName;
|
||||
// Return the names of the functions that hold sync on the object, or nil if none.
|
||||
+ (NSArray * GTM_NULLABLE_TYPE)functionsHoldingSynchronizationOnObject:(id)object;
|
||||
+ (nullable NSArray *)functionsHoldingSynchronizationOnObject:(id)object;
|
||||
@end
|
||||
|
||||
#else
|
||||
#define GTMSessionMonitorSynchronized(obj) do { } while (0)
|
||||
#define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0)
|
||||
#define GTMSessionCheckSynchronized(obj) do { } while (0)
|
||||
#define GTMSessionCheckNotSynchronized(obj) do { } while (0)
|
||||
#define GTMSessionMonitorSynchronized(obj) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define GTMSessionMonitorRecursiveSynchronized(obj) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define GTMSessionCheckSynchronized(obj) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define GTMSessionCheckNotSynchronized(obj) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif // !DEBUG
|
||||
#endif // __OBJC__
|
||||
|
||||
|
||||
GTM_ASSUME_NONNULL_END
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
1525
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m
generated
1525
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m
generated
File diff suppressed because it is too large
Load Diff
@ -82,10 +82,9 @@
|
||||
+ (void)setLoggingDateStamp:(NSString *)dateStamp;
|
||||
+ (NSString *)loggingDateStamp;
|
||||
|
||||
// client apps can specify the directory for the log for this specific run,
|
||||
// typically to match the directory used by another fetcher class, like:
|
||||
// client apps can specify the directory for the log for this specific run:
|
||||
//
|
||||
// [GTMSessionFetcher setLogDirectoryForCurrentRun:[GTMHTTPFetcher logDirectoryForCurrentRun]];
|
||||
// [GTMSessionFetcher setLogDirectoryForCurrentRun:logDirectoryPath];
|
||||
//
|
||||
// Setting this overrides the logging directory, process name, and date stamp when writing
|
||||
// the log file.
|
||||
|
||||
181
Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m
generated
181
Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m
generated
@ -23,7 +23,7 @@
|
||||
#import "GTMSessionFetcherLogging.h"
|
||||
|
||||
#ifndef STRIP_GTM_FETCH_LOGGING
|
||||
#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined.
|
||||
#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined.
|
||||
#endif
|
||||
|
||||
#if !STRIP_GTM_FETCH_LOGGING
|
||||
@ -45,15 +45,15 @@
|
||||
|
||||
+ (instancetype)inputStreamWithStream:(NSInputStream *)input;
|
||||
|
||||
@property (assign) id readDelegate;
|
||||
@property (assign) SEL readSelector;
|
||||
@property(assign) id readDelegate;
|
||||
@property(assign) SEL readSelector;
|
||||
|
||||
@end
|
||||
#else
|
||||
@class GTMReadMonitorInputStream;
|
||||
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||
|
||||
@interface GTMSessionFetcher (GTMHTTPFetcherLoggingUtilities)
|
||||
@interface GTMSessionFetcher (GTMSessionFetcherLoggingUtilities)
|
||||
|
||||
+ (NSString *)headersStringForDictionary:(NSDictionary *)dict;
|
||||
+ (NSString *)snipSubstringOfString:(NSString *)originalStr
|
||||
@ -157,7 +157,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
if (![fileMgr createDirectoryAtPath:logDirectory
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:NULL]) return nil;
|
||||
error:NULL])
|
||||
return nil;
|
||||
}
|
||||
gLogDirectoryForCurrentRun = logDirectory;
|
||||
|
||||
@ -243,18 +244,15 @@ static NSString *gLoggingProcessName = nil;
|
||||
if ([itemURL isEqual:logDirectoryForCurrentRun]) continue;
|
||||
|
||||
NSDate *modDate;
|
||||
if ([itemURL getResourceValue:&modDate
|
||||
forKey:NSURLContentModificationDateKey
|
||||
error:&error]) {
|
||||
if ([itemURL getResourceValue:&modDate forKey:NSURLContentModificationDateKey error:&error]) {
|
||||
if ([modDate compare:cutoffDate] == NSOrderedAscending) {
|
||||
if (![fileMgr removeItemAtURL:itemURL error:&error]) {
|
||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@",
|
||||
itemURL.path, error);
|
||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", itemURL.path, error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@",
|
||||
itemURL.path, error);
|
||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", itemURL.path,
|
||||
error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,9 +267,10 @@ static NSString *gLoggingProcessName = nil;
|
||||
// if the content type is JSON and we have the parsing class available, use that
|
||||
if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) {
|
||||
// convert from JSON string to NSObjects and back to a formatted string
|
||||
NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:inputData
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:NULL];
|
||||
NSMutableDictionary *obj =
|
||||
[NSJSONSerialization JSONObjectWithData:inputData
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:NULL];
|
||||
if (obj) {
|
||||
if (outJSON) *outJSON = obj;
|
||||
if ([obj isKindOfClass:[NSMutableDictionary class]]) {
|
||||
@ -287,8 +286,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
options:NSJSONWritingPrettyPrinted
|
||||
error:NULL];
|
||||
if (data) {
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
return jsonStr;
|
||||
}
|
||||
}
|
||||
@ -305,10 +303,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath];
|
||||
gHasCheckedAvailability = YES;
|
||||
}
|
||||
if (gIsXMLLintAvailable
|
||||
&& inputData.length > 5
|
||||
&& strncmp(inputData.bytes, "<?xml", 5) == 0) {
|
||||
|
||||
if (gIsXMLLintAvailable && inputData.length > 5 && strncmp(inputData.bytes, "<?xml", 5) == 0) {
|
||||
// call xmllint to format the data
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:kXMLLintPath];
|
||||
@ -342,8 +337,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
// we can't call external tasks on the iPhone; leave the XML unformatted
|
||||
#endif
|
||||
|
||||
NSString *dataStr = [[NSString alloc] initWithData:inputData
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSString *dataStr = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
|
||||
return dataStr;
|
||||
}
|
||||
|
||||
@ -356,15 +350,11 @@ static NSString *gLoggingProcessName = nil;
|
||||
// For parts that fail, a replacement string showing the part header and <<n bytes>> is supplied
|
||||
// in place of the binary data.
|
||||
|
||||
- (NSString *)stringFromStreamData:(NSData *)data
|
||||
contentType:(NSString *)contentType {
|
||||
|
||||
- (NSString *)stringFromStreamData:(NSData *)data contentType:(NSString *)contentType {
|
||||
if (!data) return nil;
|
||||
|
||||
// optimistically, see if the whole data block is UTF-8
|
||||
NSString *streamDataStr = [self formattedStringFromData:data
|
||||
contentType:contentType
|
||||
JSON:NULL];
|
||||
NSString *streamDataStr = [self formattedStringFromData:data contentType:contentType JSON:NULL];
|
||||
if (streamDataStr) return streamDataStr;
|
||||
|
||||
// Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an
|
||||
@ -378,17 +368,13 @@ static NSString *gLoggingProcessName = nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *mungedStr = [[NSString alloc] initWithData:mutableData
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSString *mungedStr = [[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding];
|
||||
if (mungedStr) {
|
||||
|
||||
// scan for the boundary string
|
||||
NSString *boundary = nil;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:mungedStr];
|
||||
|
||||
if ([scanner scanUpToString:@"\r\n" intoString:&boundary]
|
||||
&& [boundary hasPrefix:@"--"]) {
|
||||
|
||||
if ([scanner scanUpToString:@"\r\n" intoString:&boundary] && [boundary hasPrefix:@"--"]) {
|
||||
// we found a boundary string; use it to divide the string into parts
|
||||
NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary];
|
||||
|
||||
@ -412,8 +398,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
header = @"";
|
||||
}
|
||||
// make a part string with the header and <<n bytes>>
|
||||
NSString *binStr = [NSString stringWithFormat:@"\r%@\r<<%lu bytes>>\r",
|
||||
header, (long)(partSize - header.length)];
|
||||
NSString *binStr = [NSString
|
||||
stringWithFormat:@"\r%@\r<<%lu bytes>>\r", header, (long)(partSize - header.length)];
|
||||
[origParts addObject:binStr];
|
||||
}
|
||||
offset += partSize + boundary.length;
|
||||
@ -465,10 +451,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
int64_t responseDataLength = self.downloadedLength;
|
||||
if (responseDataLength > 0) {
|
||||
NSData *downloadedData = self.downloadedData;
|
||||
if (downloadedData == nil
|
||||
&& responseDataLength > 0
|
||||
&& responseDataLength < 20000
|
||||
&& self.destinationFileURL) {
|
||||
if (downloadedData == nil && responseDataLength > 0 && responseDataLength < 20000 &&
|
||||
self.destinationFileURL) {
|
||||
// There's a download file that's not too big, so get the data to display from the downloaded
|
||||
// file.
|
||||
NSURL *destinationURL = self.destinationFileURL;
|
||||
@ -482,8 +466,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSData *dataToWrite = nil;
|
||||
if (responseDataStr) {
|
||||
// we were able to make a UTF-8 string from the response data
|
||||
if ([responseMIMEType isEqual:@"application/atom+xml"]
|
||||
|| [responseMIMEType hasSuffix:@"/xml"]) {
|
||||
if ([responseMIMEType isEqual:@"application/atom+xml"] ||
|
||||
[responseMIMEType hasSuffix:@"/xml"]) {
|
||||
responseDataExtn = @"xml";
|
||||
dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
@ -505,34 +489,38 @@ static NSString *gLoggingProcessName = nil;
|
||||
// if we have an extension, save the raw data in a file with that extension
|
||||
if (responseDataExtn && dataToWrite) {
|
||||
// generate a response file base name like
|
||||
NSString *responseBaseName = [NSString stringWithFormat:@"fetch_%d_response", responseCounter];
|
||||
NSString *responseBaseName =
|
||||
[NSString stringWithFormat:@"fetch_%d_response", responseCounter];
|
||||
responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn];
|
||||
NSString *responseDataFilePath = [logDirectory stringByAppendingPathComponent:responseDataFileName];
|
||||
NSString *responseDataFilePath =
|
||||
[logDirectory stringByAppendingPathComponent:responseDataFileName];
|
||||
|
||||
NSError *downloadedError = nil;
|
||||
if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath
|
||||
options:0
|
||||
error:&downloadedError]) {
|
||||
NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, responseDataFileName);
|
||||
NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError,
|
||||
responseDataFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// we'll have one main html file per run of the app
|
||||
NSString *htmlName = [[self class] htmlFileName];
|
||||
NSString *htmlPath =[logDirectory stringByAppendingPathComponent:htmlName];
|
||||
NSString *htmlPath = [logDirectory stringByAppendingPathComponent:htmlName];
|
||||
|
||||
// if the html file exists (from logging previous fetches) we don't need
|
||||
// to re-write the header or the scripts
|
||||
NSFileManager *fileMgr = [NSFileManager defaultManager];
|
||||
BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath];
|
||||
|
||||
NSMutableString* outputHTML = [NSMutableString string];
|
||||
NSMutableString *outputHTML = [NSMutableString string];
|
||||
|
||||
// we need a header to say we'll have UTF-8 text
|
||||
if (!didFileExist) {
|
||||
[outputHTML appendFormat:@"<html><head><meta http-equiv=\"content-type\" "
|
||||
"content=\"text/html; charset=UTF-8\"><title>%@ HTTP fetch log %@</title>",
|
||||
processName, [[self class] loggingDateStamp]];
|
||||
[outputHTML
|
||||
appendFormat:@"<html><head><meta http-equiv=\"content-type\" "
|
||||
"content=\"text/html; charset=UTF-8\"><title>%@ HTTP fetch log %@</title>",
|
||||
processName, [[self class] loggingDateStamp]];
|
||||
}
|
||||
// now write the visible html elements
|
||||
NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter];
|
||||
@ -545,7 +533,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
if (comment.length > 0) {
|
||||
[outputHTML appendFormat:@"%@ ", comment];
|
||||
}
|
||||
[outputHTML appendFormat:@"</b><a href='%@'><i>request/response log</i></a><br>", copyableFileName];
|
||||
[outputHTML
|
||||
appendFormat:@"</b><a href='%@'><i>request/response log</i></a><br>", copyableFileName];
|
||||
NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow;
|
||||
[outputHTML appendFormat:@"elapsed: %5.3fsec<br>", elapsed];
|
||||
|
||||
@ -559,7 +548,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
self.redirectedFromURL = [requestURL copy];
|
||||
if (redirectedFromURLString) {
|
||||
[outputHTML appendFormat:@"<FONT COLOR='#990066'><i>redirected from %@</i></FONT><br>",
|
||||
redirectedFromURLString];
|
||||
redirectedFromURLString];
|
||||
}
|
||||
[outputHTML appendFormat:@"<b>request:</b> %@ <code>%@</code><br>\n", requestMethod, requestURL];
|
||||
|
||||
@ -590,10 +579,11 @@ static NSString *gLoggingProcessName = nil;
|
||||
}
|
||||
matchHdr = [requestHeaders objectForKey:@"If-None-Match"];
|
||||
if (matchHdr) {
|
||||
headerDetails = [headerDetails stringByAppendingString:@" <i>if-none-match</i>"];
|
||||
headerDetails =
|
||||
[headerDetails stringByAppendingString:@" <i>if-none-match</i>"];
|
||||
}
|
||||
[outputHTML appendFormat:@" headers: %d %@<br>",
|
||||
(int)numberOfRequestHeaders, headerDetails];
|
||||
[outputHTML appendFormat:@" headers: %d %@<br>", (int)numberOfRequestHeaders,
|
||||
headerDetails];
|
||||
} else {
|
||||
[outputHTML appendFormat:@" headers: none<br>"];
|
||||
}
|
||||
@ -633,14 +623,13 @@ static NSString *gLoggingProcessName = nil;
|
||||
|
||||
if (bodyDataLength > 0) {
|
||||
[outputHTML appendFormat:@" data: %llu bytes, <code>%@</code><br>\n",
|
||||
bodyDataLength, postType ? postType : @"(no type)"];
|
||||
bodyDataLength, postType ? postType : @"(no type)"];
|
||||
NSString *logRequestBody = self.logRequestBody;
|
||||
if (logRequestBody) {
|
||||
bodyDataStr = [logRequestBody copy];
|
||||
self.logRequestBody = nil;
|
||||
} else {
|
||||
bodyDataStr = [self stringFromStreamData:bodyData
|
||||
contentType:postType];
|
||||
bodyDataStr = [self stringFromStreamData:bodyData contentType:postType];
|
||||
if (bodyDataStr) {
|
||||
// remove OAuth 2 client secret and refresh token
|
||||
bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr
|
||||
@ -674,17 +663,17 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSString *jsonMessage = [jsonError valueForKey:@"message"];
|
||||
if (jsonCode || jsonMessage) {
|
||||
// 2691 = ⚑
|
||||
NSString *const jsonErrFmt =
|
||||
@" <i>JSON error:</i> <FONT COLOR='#FF00FF'>%@ %@ ⚑</FONT>";
|
||||
statusString = [statusString stringByAppendingFormat:jsonErrFmt,
|
||||
jsonCode ? jsonCode : @"",
|
||||
jsonMessage ? jsonMessage : @""];
|
||||
NSString *const jsonErrFmt = @" <i>JSON error:</i> <FONT "
|
||||
@"COLOR='#FF00FF'>%@ %@ ⚑</FONT>";
|
||||
statusString =
|
||||
[statusString stringByAppendingFormat:jsonErrFmt, jsonCode ? jsonCode : @"",
|
||||
jsonMessage ? jsonMessage : @""];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// purple for anything other than 200 or 201
|
||||
NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑
|
||||
NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑
|
||||
NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status];
|
||||
NSString *const statusFormat = @"<FONT COLOR='#FF00FF'>%ld %@ %@</FONT>";
|
||||
statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag];
|
||||
@ -699,8 +688,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
@"<FONT COLOR='#FF00FF'>response URL:</FONT> <code>%@</code><br>\n";
|
||||
responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]];
|
||||
}
|
||||
[outputHTML appendFormat:@"<b>response:</b> status %@<br>\n%@",
|
||||
statusString, responseURLStr];
|
||||
[outputHTML appendFormat:@"<b>response:</b> status %@<br>\n%@", statusString,
|
||||
responseURLStr];
|
||||
// Write the response headers
|
||||
NSUInteger numberOfResponseHeaders = responseHeaders.count;
|
||||
if (numberOfResponseHeaders > 0) {
|
||||
@ -714,7 +703,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSString *redirectsStr =
|
||||
isRedirect ? @" <FONT COLOR='#990066'><i>redirects</i></FONT>" : @"";
|
||||
[outputHTML appendFormat:@" headers: %d %@ %@<br>\n",
|
||||
(int)numberOfResponseHeaders, cookiesStr, redirectsStr];
|
||||
(int)numberOfResponseHeaders, cookiesStr, redirectsStr];
|
||||
} else {
|
||||
[outputHTML appendString:@" headers: none<br>\n"];
|
||||
}
|
||||
@ -728,21 +717,22 @@ static NSString *gLoggingProcessName = nil;
|
||||
if (isResponseImage) {
|
||||
// Make a small inline image that links to the full image file
|
||||
[outputHTML appendFormat:@" data: %lld bytes, <code>%@</code><br>",
|
||||
responseDataLength, responseMIMEType];
|
||||
NSString *const fmt =
|
||||
@"<a href=\"%@\"><img src='%@' alt='image' style='border:solid thin;max-height:32'></a>\n";
|
||||
responseDataLength, responseMIMEType];
|
||||
NSString *const fmt = @"<a href=\"%@\"><img src='%@' alt='image' style='border:solid "
|
||||
@"thin;max-height:32'></a>\n";
|
||||
[outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName];
|
||||
} else {
|
||||
// The response data was XML; link to the xml file
|
||||
NSString *const fmt =
|
||||
@" data: %lld bytes, <code>%@</code> <i><a href=\"%@\">%@</a></i>\n";
|
||||
[outputHTML appendFormat:fmt, responseDataLength, responseMIMEType,
|
||||
responseDataFileName, [responseDataFileName pathExtension]];
|
||||
NSString *const fmt = @" data: %lld bytes, "
|
||||
@"<code>%@</code> <i><a href=\"%@\">%@</a></i>\n";
|
||||
[outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, responseDataFileName,
|
||||
[responseDataFileName pathExtension]];
|
||||
}
|
||||
} else {
|
||||
// The response data was not an image; just show the length and MIME type
|
||||
[outputHTML appendFormat:@" data: %lld bytes, <code>%@</code>\n",
|
||||
responseDataLength, responseMIMEType ? responseMIMEType : @"(no response type)"];
|
||||
responseDataLength,
|
||||
responseMIMEType ? responseMIMEType : @"(no response type)"];
|
||||
}
|
||||
// Make a single string of the request and response, suitable for copying
|
||||
// to the clipboard and pasting into a bug report
|
||||
@ -757,7 +747,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
[copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL];
|
||||
if (requestHeaders.count > 0) {
|
||||
[copyable appendFormat:@"Request headers:\n%@\n",
|
||||
[[self class] headersStringForDictionary:requestHeaders]];
|
||||
[[self class] headersStringForDictionary:requestHeaders]];
|
||||
}
|
||||
if (bodyDataLength > 0) {
|
||||
[copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength];
|
||||
@ -767,9 +757,9 @@ static NSString *gLoggingProcessName = nil;
|
||||
[copyable appendString:@"\n"];
|
||||
}
|
||||
if (response) {
|
||||
[copyable appendFormat:@"Response: status %d\n", (int) status];
|
||||
[copyable appendFormat:@"Response: status %d\n", (int)status];
|
||||
[copyable appendFormat:@"Response headers:\n%@\n",
|
||||
[[self class] headersStringForDictionary:responseHeaders]];
|
||||
[[self class] headersStringForDictionary:responseHeaders]];
|
||||
[copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength];
|
||||
if (responseDataLength > 0) {
|
||||
NSString *logResponseBody = self.logResponseBody;
|
||||
@ -783,8 +773,8 @@ static NSString *gLoggingProcessName = nil;
|
||||
} else {
|
||||
// Even though it's redundant, we'll put in text to indicate that all the bytes are binary.
|
||||
if (self.destinationFileURL) {
|
||||
[copyable appendFormat:@"<<%lld bytes>> to file %@\n",
|
||||
responseDataLength, self.destinationFileURL.path];
|
||||
[copyable appendFormat:@"<<%lld bytes>> to file %@\n", responseDataLength,
|
||||
self.destinationFileURL.path];
|
||||
} else {
|
||||
[copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength];
|
||||
}
|
||||
@ -819,11 +809,10 @@ static NSString *gLoggingProcessName = nil;
|
||||
[outputHTML appendString:@"<br><hr><p>"];
|
||||
|
||||
// Append the HTML to the main output file
|
||||
const char* htmlBytes = outputHTML.UTF8String;
|
||||
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath
|
||||
append:YES];
|
||||
const char *htmlBytes = outputHTML.UTF8String;
|
||||
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath append:YES];
|
||||
[stream open];
|
||||
[stream write:(const uint8_t *) htmlBytes maxLength:strlen(htmlBytes)];
|
||||
[stream write:(const uint8_t *)htmlBytes maxLength:strlen(htmlBytes)];
|
||||
[stream close];
|
||||
|
||||
// Make a symlink to the latest html
|
||||
@ -832,9 +821,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName];
|
||||
|
||||
[fileMgr removeItemAtPath:symlinkPath error:NULL];
|
||||
[fileMgr createSymbolicLinkAtPath:symlinkPath
|
||||
withDestinationPath:htmlPath
|
||||
error:NULL];
|
||||
[fileMgr createSymbolicLinkAtPath:symlinkPath withDestinationPath:htmlPath error:NULL];
|
||||
#if TARGET_OS_IPHONE
|
||||
static BOOL gReportedLoggingPath = NO;
|
||||
if (!gReportedLoggingPath) {
|
||||
@ -882,11 +869,11 @@ static NSString *gLoggingProcessName = nil;
|
||||
}
|
||||
GTMSessionFetcherBodyStreamProvider loggedStreamProvider =
|
||||
^(GTMSessionFetcherBodyStreamProviderResponse response) {
|
||||
streamProvider(^(NSInputStream *bodyStream) {
|
||||
streamProvider(^(NSInputStream *bodyStream) {
|
||||
bodyStream = [self loggedInputStreamForInputStream:bodyStream];
|
||||
response(bodyStream);
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
return loggedStreamProvider;
|
||||
}
|
||||
|
||||
@ -898,9 +885,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
readIntoBuffer:(void *)buffer
|
||||
length:(int64_t)length {
|
||||
// append the captured data
|
||||
NSData *data = [NSData dataWithBytesNoCopy:buffer
|
||||
length:(NSUInteger)length
|
||||
freeWhenDone:NO];
|
||||
NSData *data = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)length freeWhenDone:NO];
|
||||
[self appendLoggedStreamData:data];
|
||||
}
|
||||
|
||||
@ -923,9 +908,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSUInteger originalLength = originalStr.length;
|
||||
NSUInteger startOfTarget = NSMaxRange(startRange);
|
||||
NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget);
|
||||
NSRange endRange = [originalStr rangeOfString:endStr
|
||||
options:0
|
||||
range:targetAndRest];
|
||||
NSRange endRange = [originalStr rangeOfString:endStr options:0 range:targetAndRest];
|
||||
NSRange replaceRange;
|
||||
if (endRange.location == NSNotFound) {
|
||||
// Found no end marker so replace to end of string
|
||||
@ -937,7 +920,7 @@ static NSString *gLoggingProcessName = nil;
|
||||
NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange
|
||||
withString:@"_snip_"];
|
||||
return result;
|
||||
#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING
|
||||
#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING
|
||||
}
|
||||
|
||||
+ (NSString *)headersStringForDictionary:(NSDictionary *)dict {
|
||||
@ -979,4 +962,4 @@ static NSString *gLoggingProcessName = nil;
|
||||
|
||||
@end
|
||||
|
||||
#endif // !STRIP_GTM_FETCH_LOGGING
|
||||
#endif // !STRIP_GTM_FETCH_LOGGING
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
#import "GTMSessionFetcher.h"
|
||||
|
||||
GTM_ASSUME_NONNULL_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// Notifications.
|
||||
|
||||
@ -34,12 +34,14 @@ GTM_ASSUME_NONNULL_BEGIN
|
||||
extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification;
|
||||
extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
|
||||
@interface GTMSessionFetcherService : NSObject<GTMSessionFetcherServiceProtocol>
|
||||
@interface GTMSessionFetcherService : NSObject <GTMSessionFetcherServiceProtocol>
|
||||
|
||||
// Queues of delayed and running fetchers. Each dictionary contains arrays
|
||||
// of GTMSessionFetcher *fetchers, keyed by NSString *host
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *delayedFetchersByHost;
|
||||
@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *runningFetchersByHost;
|
||||
@property(atomic, strong, readonly, nullable)
|
||||
NSDictionary<NSString *, NSArray *> *delayedFetchersByHost;
|
||||
@property(atomic, strong, readonly, nullable)
|
||||
NSDictionary<NSString *, NSArray *> *runningFetchersByHost;
|
||||
|
||||
// A max value of 0 means no fetchers should be delayed.
|
||||
// The default limit is 10 simultaneous fetchers targeting each host.
|
||||
@ -48,24 +50,24 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
@property(atomic, assign) NSUInteger maxRunningFetchersPerHost;
|
||||
|
||||
// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration;
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage;
|
||||
@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue;
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential;
|
||||
@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock;
|
||||
@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage;
|
||||
@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock;
|
||||
@property(atomic, strong, nullable) NSURLCredential *credential;
|
||||
@property(atomic, strong) NSURLCredential *proxyCredential;
|
||||
@property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes;
|
||||
@property(atomic, copy, nullable) NSArray<NSString *> *allowedInsecureSchemes;
|
||||
@property(atomic, assign) BOOL allowLocalhostRequest;
|
||||
@property(atomic, assign) BOOL allowInvalidServerCertificates;
|
||||
@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock;
|
||||
@property(atomic, assign) NSTimeInterval maxRetryInterval;
|
||||
@property(atomic, assign) NSTimeInterval minRetryInterval;
|
||||
@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties;
|
||||
@property(atomic, copy, GTM_NULLABLE)
|
||||
@property(atomic, copy, nullable) NSDictionary<NSString *, id> *properties;
|
||||
@property(atomic, copy, nullable)
|
||||
GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
|
||||
ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0));
|
||||
ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0));
|
||||
|
||||
#if GTM_BACKGROUND_TASK_FETCHING
|
||||
@property(atomic, assign) BOOL skipBackgroundTask;
|
||||
@ -76,17 +78,17 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9.
|
||||
//
|
||||
// To use the configuration's default user agent, set this property to nil.
|
||||
@property(atomic, copy, GTM_NULLABLE) NSString *userAgent;
|
||||
@property(atomic, copy, nullable) NSString *userAgent;
|
||||
|
||||
// The authorizer to attach to the created fetchers. If a specific fetcher should
|
||||
// not authorize its requests, the fetcher's authorizer property may be set to nil
|
||||
// before the fetch begins.
|
||||
@property(atomic, strong, GTM_NULLABLE) id<GTMFetcherAuthorizationProtocol> authorizer;
|
||||
@property(atomic, strong, nullable) id<GTMFetcherAuthorizationProtocol> authorizer;
|
||||
|
||||
// Delegate queue used by the session when calling back to the fetcher. The default
|
||||
// is the main queue. Changing this does not affect the queue used to call back to the
|
||||
// application; that is specified by the callbackQueue property above.
|
||||
@property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue;
|
||||
@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue;
|
||||
|
||||
// When enabled, indicates the same session should be used by subsequent fetchers.
|
||||
//
|
||||
@ -120,12 +122,11 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of
|
||||
// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to
|
||||
// be overridden.
|
||||
- (id)fetcherWithRequest:(NSURLRequest *)request
|
||||
fetcherClass:(Class)fetcherClass;
|
||||
- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass;
|
||||
|
||||
- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
|
||||
|
||||
- (NSUInteger)numberOfFetchers; // running + delayed fetchers
|
||||
- (NSUInteger)numberOfFetchers; // running + delayed fetchers
|
||||
- (NSUInteger)numberOfRunningFetchers;
|
||||
- (NSUInteger)numberOfDelayedFetchers;
|
||||
|
||||
@ -133,24 +134,33 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
// by the service which have been started and have not yet stopped.
|
||||
//
|
||||
// Returns an array of fetcher objects, or nil if none.
|
||||
- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchers;
|
||||
- (nullable NSArray<GTMSessionFetcher *> *)issuedFetchers;
|
||||
|
||||
// Search for running or delayed fetchers with the specified URL.
|
||||
//
|
||||
// Returns an array of fetcher objects found, or nil if none found.
|
||||
- (GTM_NULLABLE GTM_NSArrayOf(GTMSessionFetcher *) *)issuedFetchersWithRequestURL:(NSURL *)requestURL;
|
||||
- (nullable NSArray<GTMSessionFetcher *> *)issuedFetchersWithRequestURL:(NSURL *)requestURL;
|
||||
|
||||
- (void)stopAllFetchers;
|
||||
|
||||
// Holds a weak reference to `decorator`. When creating a fetcher via
|
||||
// `-fetcherWithRequest:fetcherClass:`, each registered `decorator` can inspect and potentially
|
||||
// change the fetcher's request before it starts. Decorators are invoked in the order in which
|
||||
// they are passed to this method.
|
||||
- (void)addDecorator:(id<GTMFetcherDecoratorProtocol>)decorator;
|
||||
|
||||
// Removes a `decorator` previously passed to `-removeDecorator:`.
|
||||
- (void)removeDecorator:(id<GTMFetcherDecoratorProtocol>)decorator;
|
||||
|
||||
// Methods for use by the fetcher class only.
|
||||
- (GTM_NULLABLE NSURLSession *)session;
|
||||
- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
|
||||
- (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
|
||||
- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
|
||||
- (nullable NSURLSession *)session;
|
||||
- (nullable NSURLSession *)sessionForFetcherCreation;
|
||||
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
|
||||
- (nullable NSDate *)stoppedAllFetchersDate;
|
||||
|
||||
// The testBlock can inspect its fetcher parameter's request property to
|
||||
// determine which fetcher is being faked.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock;
|
||||
@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock;
|
||||
|
||||
@end
|
||||
|
||||
@ -166,12 +176,14 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
// or fetcher; the test block can inspect the fetcher's request or other properties.
|
||||
//
|
||||
// See the description of the testBlock property below.
|
||||
+ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil
|
||||
fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil;
|
||||
+ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil
|
||||
+ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil
|
||||
fakedError:(nullable NSError *)fakedErrorOrNil;
|
||||
+ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil
|
||||
fakedResponse:(NSHTTPURLResponse *)fakedResponse
|
||||
fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil;
|
||||
fakedError:(nullable NSError *)fakedErrorOrNil;
|
||||
|
||||
// DEPRECATED: Callers should use XCTestExpectation instead.
|
||||
//
|
||||
// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread)
|
||||
// until all running and delayed fetchers have completed.
|
||||
//
|
||||
@ -181,16 +193,18 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||
// sufficient reason for rejection from the app store.
|
||||
//
|
||||
// Returns NO if timed out.
|
||||
- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
||||
- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds
|
||||
__deprecated_msg("Use XCTestExpectation instead");
|
||||
|
||||
@end
|
||||
|
||||
@interface GTMSessionFetcherService (BackwardsCompatibilityOnly)
|
||||
|
||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
|
||||
// This method is just for compatibility with the old fetcher.
|
||||
@property(atomic, assign) NSInteger cookieStorageMethod;
|
||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves;
|
||||
// this property is deprecated and will be removed soon.
|
||||
@property(atomic, assign) NSInteger cookieStorageMethod __deprecated_msg(
|
||||
"Create an NSHTTPCookieStorage and set .cookieStorage directly.");
|
||||
|
||||
@end
|
||||
|
||||
GTM_ASSUME_NONNULL_END
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
364
Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m
generated
364
Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m
generated
@ -19,15 +19,15 @@
|
||||
|
||||
#import "GTMSessionFetcherService.h"
|
||||
|
||||
NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification
|
||||
= @"kGTMSessionFetcherServiceSessionBecameInvalidNotification";
|
||||
NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
= @"kGTMSessionFetcherServiceSessionKey";
|
||||
NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification =
|
||||
@"kGTMSessionFetcherServiceSessionBecameInvalidNotification";
|
||||
NSString *const kGTMSessionFetcherServiceSessionKey = @"kGTMSessionFetcherServiceSessionKey";
|
||||
|
||||
#if !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||
@interface GTMSessionFetcher (ServiceMethods)
|
||||
- (BOOL)beginFetchMayDelay:(BOOL)mayDelay
|
||||
mayAuthorize:(BOOL)mayAuthorize;
|
||||
mayAuthorize:(BOOL)mayAuthorize
|
||||
mayDecorate:(BOOL)mayDecorate;
|
||||
@end
|
||||
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||
|
||||
@ -36,6 +36,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost;
|
||||
@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost;
|
||||
|
||||
// Ordered collection of id<GTMFetcherDecoratorProtocol>, held weakly.
|
||||
@property(atomic, strong, readonly) NSPointerArray *decoratorsPointerArray;
|
||||
|
||||
@end
|
||||
|
||||
// Since NSURLSession doesn't support a separate delegate per task (!), instances of this
|
||||
@ -43,7 +46,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
//
|
||||
// This class maps a session's tasks to fetchers, and resends delegate messages to the task's
|
||||
// fetcher.
|
||||
@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject<NSURLSessionDelegate>
|
||||
@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject <NSURLSessionDelegate>
|
||||
|
||||
// The session for the tasks in this dispatcher's task-to-fetcher map.
|
||||
@property(atomic) NSURLSession *session;
|
||||
@ -54,12 +57,10 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// The current discard timer.
|
||||
@property(atomic, readonly) NSTimer *discardTimer;
|
||||
|
||||
|
||||
- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService
|
||||
sessionDiscardInterval:(NSTimeInterval)discardInterval;
|
||||
|
||||
- (void)setFetcher:(GTMSessionFetcher *)fetcher
|
||||
forTask:(NSURLSessionTask *)task;
|
||||
- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task;
|
||||
- (void)removeFetcher:(GTMSessionFetcher *)fetcher;
|
||||
|
||||
// Before using a session, tells the delegate dispatcher to stop the discard timer.
|
||||
@ -71,7 +72,6 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation GTMSessionFetcherService {
|
||||
NSMutableDictionary *_delayedFetchersByHost;
|
||||
NSMutableDictionary *_runningFetchersByHost;
|
||||
@ -106,6 +106,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSDate *_stoppedAllFetchersDate;
|
||||
}
|
||||
|
||||
// Clang-format likes to cram all @synthesize items onto the fewest lines, rather than one-per.
|
||||
// clang-format off
|
||||
@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost,
|
||||
configuration = _configuration,
|
||||
configurationBlock = _configurationBlock,
|
||||
@ -124,7 +126,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
metricsCollectionBlock = _metricsCollectionBlock,
|
||||
properties = _properties,
|
||||
unusedSessionTimeout = _unusedSessionTimeout,
|
||||
decoratorsPointerArray = _decoratorsPointerArray,
|
||||
testBlock = _testBlock;
|
||||
// clang-format on
|
||||
|
||||
#if GTM_BACKGROUND_TASK_FETCHING
|
||||
@synthesize skipBackgroundTask = _skipBackgroundTask;
|
||||
@ -138,9 +142,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
_maxRunningFetchersPerHost = 10;
|
||||
_cookieStorageMethod = -1;
|
||||
_unusedSessionTimeout = 60.0;
|
||||
_delegateDispatcher =
|
||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||
initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
_callbackQueue = dispatch_get_main_queue();
|
||||
|
||||
_delegateQueue = [[NSOperationQueue alloc] init];
|
||||
@ -152,10 +156,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent.
|
||||
// Apps can remove this and get the default system "CFNetwork" useragent by setting the
|
||||
// fetcher service's userAgent property to nil.
|
||||
#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \
|
||||
|| (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0)
|
||||
_userAgent = GTMFetcherStandardUserAgentString(nil);
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -168,8 +169,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
#pragma mark Generate a new fetcher
|
||||
|
||||
// Clients may override this method. Clients should not override any other library methods.
|
||||
- (id)fetcherWithRequest:(NSURLRequest *)request
|
||||
fetcherClass:(Class)fetcherClass {
|
||||
- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass {
|
||||
GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request
|
||||
configuration:self.configuration];
|
||||
fetcher.callbackQueue = self.callbackQueue;
|
||||
@ -187,24 +187,25 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
fetcher.retryBlock = self.retryBlock;
|
||||
fetcher.maxRetryInterval = self.maxRetryInterval;
|
||||
fetcher.minRetryInterval = self.minRetryInterval;
|
||||
if (@available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)) {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
fetcher.metricsCollectionBlock = self.metricsCollectionBlock;
|
||||
}
|
||||
fetcher.properties = self.properties;
|
||||
fetcher.service = self;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (self.cookieStorageMethod >= 0) {
|
||||
[fetcher setCookieStorageMethod:self.cookieStorageMethod];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#if GTM_BACKGROUND_TASK_FETCHING
|
||||
fetcher.skipBackgroundTask = self.skipBackgroundTask;
|
||||
#endif
|
||||
|
||||
NSString *userAgent = self.userAgent;
|
||||
if (userAgent.length > 0
|
||||
&& [request valueForHTTPHeaderField:@"User-Agent"] == nil) {
|
||||
[fetcher setRequestValue:userAgent
|
||||
forHTTPHeaderField:@"User-Agent"];
|
||||
if (userAgent.length > 0 && [request valueForHTTPHeaderField:@"User-Agent"] == nil) {
|
||||
[fetcher setRequestValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||
}
|
||||
fetcher.testBlock = self.testBlock;
|
||||
|
||||
@ -212,8 +213,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
}
|
||||
|
||||
- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request {
|
||||
return [self fetcherWithRequest:request
|
||||
fetcherClass:[GTMSessionFetcher class]];
|
||||
return [self fetcherWithRequest:request fetcherClass:[GTMSessionFetcher class]];
|
||||
}
|
||||
|
||||
- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL {
|
||||
@ -225,6 +225,39 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
return [self fetcherWithURL:url];
|
||||
}
|
||||
|
||||
- (void)addDecorator:(id<GTMFetcherDecoratorProtocol>)decorator {
|
||||
@synchronized(self) {
|
||||
if (!_decoratorsPointerArray) {
|
||||
_decoratorsPointerArray = [NSPointerArray weakObjectsPointerArray];
|
||||
}
|
||||
[_decoratorsPointerArray addPointer:(__bridge void *)decorator];
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSArray<id<GTMFetcherDecoratorProtocol>> *)decorators {
|
||||
@synchronized(self) {
|
||||
return _decoratorsPointerArray.allObjects;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeDecorator:(id<GTMFetcherDecoratorProtocol>)decorator {
|
||||
@synchronized(self) {
|
||||
NSUInteger i = 0;
|
||||
for (id<GTMFetcherDecoratorProtocol> decoratorCandidate in _decoratorsPointerArray) {
|
||||
if (decoratorCandidate == decorator) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
GTMSESSION_ASSERT_DEBUG(i < _decoratorsPointerArray.count,
|
||||
@"decorator %@ must be passed to -addDecorator: before removing",
|
||||
decorator);
|
||||
if (i < _decoratorsPointerArray.count) {
|
||||
[_decoratorsPointerArray removePointerAtIndex:i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a session for the fetcher's host, or nil.
|
||||
- (NSURLSession *)session {
|
||||
@synchronized(self) {
|
||||
@ -284,8 +317,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
|
||||
#pragma mark Queue Management
|
||||
|
||||
- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher
|
||||
forHost:(NSString *)host {
|
||||
- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host {
|
||||
// Add to the array of running fetchers for this host, creating the array if needed.
|
||||
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
||||
if (runningForHost == nil) {
|
||||
@ -296,8 +328,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher
|
||||
forHost:(NSString *)host {
|
||||
- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host {
|
||||
// Add to the array of delayed fetchers for this host, creating the array if needed.
|
||||
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
||||
if (delayedForHost == nil) {
|
||||
@ -345,16 +376,14 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
||||
if (runningForHost != nil
|
||||
&& [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) {
|
||||
if (runningForHost != nil && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) {
|
||||
GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher);
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL shouldRunNow = (fetcher.usingBackgroundSession
|
||||
|| _maxRunningFetchersPerHost == 0
|
||||
|| _maxRunningFetchersPerHost >
|
||||
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost]);
|
||||
BOOL shouldRunNow = (fetcher.usingBackgroundSession || _maxRunningFetchersPerHost == 0 ||
|
||||
_maxRunningFetchersPerHost >
|
||||
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost]);
|
||||
if (shouldRunNow) {
|
||||
[self addRunningFetcher:fetcher forHost:host];
|
||||
shouldBeginResult = YES;
|
||||
@ -373,13 +402,13 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
}
|
||||
|
||||
- (void)startFetcher:(GTMSessionFetcher *)fetcher {
|
||||
[fetcher beginFetchMayDelay:NO
|
||||
mayAuthorize:YES];
|
||||
[fetcher beginFetchMayDelay:NO mayAuthorize:YES mayDecorate:YES];
|
||||
}
|
||||
|
||||
// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher
|
||||
// is its own delegate (possibly via proxy) and has no dispatcher.
|
||||
- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:(GTMSessionFetcher *)fetcher {
|
||||
- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:
|
||||
(GTMSessionFetcher *)fetcher {
|
||||
GTMSessionCheckNotSynchronized(self);
|
||||
|
||||
NSURLSession *fetcherSession = fetcher.session;
|
||||
@ -388,11 +417,12 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// If the delegate is non-nil and claims to be a GTMSessionFetcher, there is no dispatcher;
|
||||
// assume the fetcher is the delegate or has been proxied (some third-party frameworks
|
||||
// are known to swizzle NSURLSession to proxy its delegate).
|
||||
BOOL hasDispatcher = (fetcherDelegate != nil &&
|
||||
![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]);
|
||||
BOOL hasDispatcher =
|
||||
(fetcherDelegate != nil && ![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]);
|
||||
if (hasDispatcher) {
|
||||
GTMSESSION_ASSERT_DEBUG([fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]],
|
||||
@"Fetcher delegate class: %@", [fetcherDelegate class]);
|
||||
GTMSESSION_ASSERT_DEBUG(
|
||||
[fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]],
|
||||
@"Fetcher delegate class: %@", [fetcherDelegate class]);
|
||||
return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate;
|
||||
}
|
||||
}
|
||||
@ -425,8 +455,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher =
|
||||
[self delegateDispatcherForFetcher:fetcher];
|
||||
if (delegateDispatcher) {
|
||||
GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession,
|
||||
@"Inappropriate shared session: %@", fetcher);
|
||||
GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, @"Inappropriate shared session: %@", fetcher);
|
||||
|
||||
// There should already be a session, from this or a previous fetcher.
|
||||
//
|
||||
@ -435,16 +464,15 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSURLSession *fetcherSession = fetcher.session;
|
||||
GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher);
|
||||
GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession,
|
||||
@"Inconsistent session: %@ %@ (shared: %@)",
|
||||
fetcher, fetcherSession, sharedSession);
|
||||
@"Inconsistent session: %@ %@ (shared: %@)", fetcher, fetcherSession,
|
||||
sharedSession);
|
||||
|
||||
if (sharedSession != nil && fetcherSession == sharedSession) {
|
||||
NSURLSessionTask *task = fetcher.sessionTask;
|
||||
GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher);
|
||||
|
||||
if (task) {
|
||||
[delegateDispatcher setFetcher:fetcher
|
||||
forTask:task];
|
||||
[delegateDispatcher setFetcher:fetcher forTask:task];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -483,15 +511,14 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
||||
[delayedForHost removeObject:fetcher];
|
||||
|
||||
while (delayedForHost.count > 0
|
||||
&& [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]
|
||||
< _maxRunningFetchersPerHost) {
|
||||
while (delayedForHost.count > 0 &&
|
||||
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost] <
|
||||
_maxRunningFetchersPerHost) {
|
||||
// Start another delayed fetcher running, scanning for the minimum
|
||||
// priority value, defaulting to FIFO for equal priorities
|
||||
GTMSessionFetcher *nextFetcher = nil;
|
||||
for (GTMSessionFetcher *delayedFetcher in delayedForHost) {
|
||||
if (nextFetcher == nil
|
||||
|| delayedFetcher.servicePriority < nextFetcher.servicePriority) {
|
||||
if (nextFetcher == nil || delayedFetcher.servicePriority < nextFetcher.servicePriority) {
|
||||
nextFetcher = delayedFetcher;
|
||||
}
|
||||
}
|
||||
@ -566,11 +593,10 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
NSMutableArray *allFetchers = [NSMutableArray array];
|
||||
void (^accumulateFetchers)(id, id, BOOL *) = ^(NSString *host,
|
||||
NSArray *fetchersForHost,
|
||||
BOOL *stop) {
|
||||
[allFetchers addObjectsFromArray:fetchersForHost];
|
||||
};
|
||||
void (^accumulateFetchers)(id, id, BOOL *) =
|
||||
^(NSString *host, NSArray *fetchersForHost, BOOL *stop) {
|
||||
[allFetchers addObjectsFromArray:fetchersForHost];
|
||||
};
|
||||
[_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers];
|
||||
[_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers];
|
||||
|
||||
@ -589,12 +615,11 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSURL *targetURL = [requestURL absoluteURL];
|
||||
|
||||
NSArray *allFetchers = [self issuedFetchers];
|
||||
NSIndexSet *indexes = [allFetchers indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher,
|
||||
NSUInteger idx,
|
||||
BOOL *stop) {
|
||||
NSURL *fetcherURL = [fetcher.request.URL absoluteURL];
|
||||
return [fetcherURL isEqual:targetURL];
|
||||
}];
|
||||
NSIndexSet *indexes = [allFetchers
|
||||
indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, NSUInteger idx, BOOL *stop) {
|
||||
NSURL *fetcherURL = [fetcher.request.URL absoluteURL];
|
||||
return [fetcherURL isEqual:targetURL];
|
||||
}];
|
||||
|
||||
NSArray *result = nil;
|
||||
if (indexes.count > 0) {
|
||||
@ -665,9 +690,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
if (shouldReuse != wasReusing) {
|
||||
[self abandonDispatcher];
|
||||
if (shouldReuse) {
|
||||
_delegateDispatcher =
|
||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||
initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
} else {
|
||||
_delegateDispatcher = nil;
|
||||
}
|
||||
@ -693,9 +718,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// The old dispatchers may be retained as delegates of any ongoing sessions by those sessions.
|
||||
if (_delegateDispatcher) {
|
||||
[self abandonDispatcher];
|
||||
_delegateDispatcher =
|
||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||
initWithParentService:self
|
||||
sessionDiscardInterval:_unusedSessionTimeout];
|
||||
}
|
||||
}
|
||||
|
||||
@ -800,11 +825,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// Use the fetcher service for the authorization fetches if the auth
|
||||
// object supports fetcher services
|
||||
if ([obj respondsToSelector:@selector(setFetcherService:)]) {
|
||||
#if GTM_USE_SESSION_FETCHER
|
||||
[obj setFetcherService:self];
|
||||
#else
|
||||
[obj setFetcherService:(id)self];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,7 +849,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
}
|
||||
}
|
||||
|
||||
- (dispatch_queue_t GTM_NONNULL_TYPE)callbackQueue {
|
||||
- (nonnull dispatch_queue_t)callbackQueue {
|
||||
@synchronized(self) {
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
@ -836,7 +857,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
} // @synchronized(self)
|
||||
}
|
||||
|
||||
- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue {
|
||||
- (void)setCallbackQueue:(dispatch_queue_t)queue {
|
||||
@synchronized(self) {
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
@ -844,7 +865,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
} // @synchronized(self)
|
||||
}
|
||||
|
||||
- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue {
|
||||
- (NSOperationQueue *)sessionDelegateQueue {
|
||||
@synchronized(self) {
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
@ -852,7 +873,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
} // @synchronized(self)
|
||||
}
|
||||
|
||||
- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue {
|
||||
- (void)setSessionDelegateQueue:(NSOperationQueue *)queue {
|
||||
@synchronized(self) {
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
|
||||
@ -886,8 +907,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSURL *url = [NSURL URLWithString:@"http://example.invalid"];
|
||||
NSHTTPURLResponse *fakedResponse =
|
||||
[[NSHTTPURLResponse alloc] initWithURL:url
|
||||
statusCode:(fakedErrorOrNil ? 500 : 200)
|
||||
HTTPVersion:@"HTTP/1.1"
|
||||
statusCode:(fakedErrorOrNil ? 500 : 200)HTTPVersion:@"HTTP/1.1"
|
||||
headerFields:nil];
|
||||
return [self mockFetcherServiceWithFakedData:fakedDataOrNil
|
||||
fakedResponse:fakedResponse
|
||||
@ -904,10 +924,10 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
#if !GTM_DISABLE_FETCHER_TEST_BLOCK
|
||||
GTMSessionFetcherService *service = [[self alloc] init];
|
||||
service.allowedInsecureSchemes = @[ @"http" ];
|
||||
service.testBlock = ^(GTMSessionFetcher *fetcherToTest,
|
||||
GTMSessionFetcherTestResponse testResponse) {
|
||||
testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil);
|
||||
};
|
||||
service.testBlock =
|
||||
^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) {
|
||||
testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil);
|
||||
};
|
||||
return service;
|
||||
#else
|
||||
GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled");
|
||||
@ -979,8 +999,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
NSTimeInterval _discardInterval;
|
||||
}
|
||||
|
||||
@synthesize discardInterval = _discardInterval,
|
||||
session = _session;
|
||||
@synthesize discardInterval = _discardInterval, session = _session;
|
||||
|
||||
- (instancetype)init {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
@ -998,10 +1017,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@ %p %@ %@",
|
||||
[self class], self,
|
||||
_session ?: @"<no session>",
|
||||
_taskToFetcherMap.count > 0 ? _taskToFetcherMap : @"<no tasks>"];
|
||||
return
|
||||
[NSString stringWithFormat:@"%@ %p %@ %@", [self class], self, _session ?: @"<no session>",
|
||||
_taskToFetcherMap.count > 0 ? _taskToFetcherMap : @"<no tasks>"];
|
||||
}
|
||||
|
||||
- (NSTimer *)discardTimer {
|
||||
@ -1177,10 +1195,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
//
|
||||
// TODO(seh): How do we route this to an appropriate fetcher?
|
||||
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
|
||||
GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@",
|
||||
[self class], self, session, error);
|
||||
GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class],
|
||||
self, session, error);
|
||||
NSDictionary *localTaskToFetcherMap;
|
||||
@synchronized(self) {
|
||||
GTMSessionMonitorSynchronized(self);
|
||||
@ -1192,31 +1209,29 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
|
||||
// Any "suspended" tasks may not have received callbacks from NSURLSession when the session
|
||||
// completes; we'll call them now.
|
||||
[localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(NSURLSessionTask *task,
|
||||
GTMSessionFetcher *fetcher,
|
||||
BOOL *stop) {
|
||||
[localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSURLSessionTask *task, GTMSessionFetcher *fetcher, BOOL *stop) {
|
||||
if (fetcher.session == session) {
|
||||
// Our delegate method URLSession:task:didCompleteWithError: will rely on
|
||||
// _taskToFetcherMap so that should still contain this fetcher.
|
||||
NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain
|
||||
code:NSURLErrorCancelled
|
||||
userInfo:nil];
|
||||
[self URLSession:session task:task didCompleteWithError:canceledError];
|
||||
} else {
|
||||
GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)",
|
||||
fetcher, fetcher.session, session);
|
||||
}
|
||||
// Our delegate method URLSession:task:didCompleteWithError: will rely on
|
||||
// _taskToFetcherMap so that should still contain this fetcher.
|
||||
NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain
|
||||
code:NSURLErrorCancelled
|
||||
userInfo:nil];
|
||||
[self URLSession:session task:task didCompleteWithError:canceledError];
|
||||
} else {
|
||||
GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", fetcher,
|
||||
fetcher.session, session);
|
||||
}
|
||||
}];
|
||||
|
||||
// Our tests rely on this notification to know the session discard timer fired.
|
||||
NSDictionary *userInfo = @{ kGTMSessionFetcherServiceSessionKey : session };
|
||||
NSDictionary *userInfo = @{kGTMSessionFetcherServiceSessionKey : session};
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification
|
||||
object:_parentService
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSURLSessionTaskDelegate
|
||||
|
||||
// NSURLSessionTaskDelegate protocol methods.
|
||||
@ -1227,68 +1242,61 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
||||
// delegate is the fetcher or this dispatcher.)
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||
newRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
||||
task:(NSURLSessionTask *)task
|
||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||
newRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
[fetcher URLSession:session
|
||||
task:task
|
||||
willPerformHTTPRedirection:response
|
||||
newRequest:request
|
||||
completionHandler:completionHandler];
|
||||
task:task
|
||||
willPerformHTTPRedirection:response
|
||||
newRequest:request
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler {
|
||||
task:(NSURLSessionTask *)task
|
||||
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
[fetcher URLSession:session
|
||||
task:task
|
||||
didReceiveChallenge:challenge
|
||||
completionHandler:handler];
|
||||
[fetcher URLSession:session task:task didReceiveChallenge:challenge completionHandler:handler];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler {
|
||||
task:(NSURLSessionTask *)task
|
||||
needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
[fetcher URLSession:session
|
||||
task:task
|
||||
needNewBodyStream:handler];
|
||||
[fetcher URLSession:session task:task needNewBodyStream:handler];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didSendBodyData:(int64_t)bytesSent
|
||||
totalBytesSent:(int64_t)totalBytesSent
|
||||
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
|
||||
task:(NSURLSessionTask *)task
|
||||
didSendBodyData:(int64_t)bytesSent
|
||||
totalBytesSent:(int64_t)totalBytesSent
|
||||
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
[fetcher URLSession:session
|
||||
task:task
|
||||
didSendBodyData:bytesSent
|
||||
totalBytesSent:totalBytesSent
|
||||
totalBytesExpectedToSend:totalBytesExpectedToSend];
|
||||
task:task
|
||||
didSendBodyData:bytesSent
|
||||
totalBytesSent:totalBytesSent
|
||||
totalBytesExpectedToSend:totalBytesExpectedToSend];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didCompleteWithError:(NSError *)error {
|
||||
task:(NSURLSessionTask *)task
|
||||
didCompleteWithError:(NSError *)error {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
|
||||
// This is the usual way tasks are removed from the task map.
|
||||
[self removeTaskFromMap:task];
|
||||
|
||||
[fetcher URLSession:session
|
||||
task:task
|
||||
didCompleteWithError:error];
|
||||
[fetcher URLSession:session task:task didCompleteWithError:error];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
|
||||
API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0)) {
|
||||
API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) {
|
||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||
[fetcher URLSession:session task:task didFinishCollectingMetrics:metrics];
|
||||
}
|
||||
@ -1296,19 +1304,19 @@ didCompleteWithError:(NSError *)error {
|
||||
// NSURLSessionDataDelegate protocol methods.
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition))handler {
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition))handler {
|
||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||
[fetcher URLSession:session
|
||||
dataTask:dataTask
|
||||
didReceiveResponse:response
|
||||
completionHandler:handler];
|
||||
dataTask:dataTask
|
||||
didReceiveResponse:response
|
||||
completionHandler:handler];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||
GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask);
|
||||
[self removeTaskFromMap:dataTask];
|
||||
@ -1318,64 +1326,58 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
||||
[self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask];
|
||||
}
|
||||
|
||||
[fetcher URLSession:session
|
||||
dataTask:dataTask
|
||||
didBecomeDownloadTask:downloadTask];
|
||||
[fetcher URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveData:(NSData *)data {
|
||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||
[fetcher URLSession:session
|
||||
dataTask:dataTask
|
||||
didReceiveData:data];
|
||||
[fetcher URLSession:session dataTask:dataTask didReceiveData:data];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
willCacheResponse:(NSCachedURLResponse *)proposedResponse
|
||||
completionHandler:(void (^)(NSCachedURLResponse *))handler {
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
willCacheResponse:(NSCachedURLResponse *)proposedResponse
|
||||
completionHandler:(void (^)(NSCachedURLResponse *))handler {
|
||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||
[fetcher URLSession:session
|
||||
dataTask:dataTask
|
||||
willCacheResponse:proposedResponse
|
||||
completionHandler:handler];
|
||||
dataTask:dataTask
|
||||
willCacheResponse:proposedResponse
|
||||
completionHandler:handler];
|
||||
}
|
||||
|
||||
// NSURLSessionDownloadDelegate protocol methods.
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didFinishDownloadingToURL:(NSURL *)location {
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didFinishDownloadingToURL:(NSURL *)location {
|
||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||
[fetcher URLSession:session
|
||||
downloadTask:downloadTask
|
||||
didFinishDownloadingToURL:location];
|
||||
[fetcher URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didWriteData:(int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalExpected {
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didWriteData:(int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalExpected {
|
||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||
[fetcher URLSession:session
|
||||
downloadTask:downloadTask
|
||||
didWriteData:bytesWritten
|
||||
totalBytesWritten:totalWritten
|
||||
totalBytesExpectedToWrite:totalExpected];
|
||||
downloadTask:downloadTask
|
||||
didWriteData:bytesWritten
|
||||
totalBytesWritten:totalWritten
|
||||
totalBytesExpectedToWrite:totalExpected];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didResumeAtOffset:(int64_t)fileOffset
|
||||
expectedTotalBytes:(int64_t)expectedTotalBytes {
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didResumeAtOffset:(int64_t)fileOffset
|
||||
expectedTotalBytes:(int64_t)expectedTotalBytes {
|
||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||
[fetcher URLSession:session
|
||||
downloadTask:downloadTask
|
||||
didResumeAtOffset:fileOffset
|
||||
expectedTotalBytes:expectedTotalBytes];
|
||||
downloadTask:downloadTask
|
||||
didResumeAtOffset:fileOffset
|
||||
expectedTotalBytes:expectedTotalBytes];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
#import "GTMSessionFetcher.h"
|
||||
#import "GTMSessionFetcherService.h"
|
||||
|
||||
GTM_ASSUME_NONNULL_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// The value to use for file size parameters when the file size is not yet known.
|
||||
extern int64_t const kGTMSessionUploadFetcherUnknownFileSize;
|
||||
@ -68,24 +68,23 @@ extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification;
|
||||
// to its proper value.
|
||||
//
|
||||
// Pass nil as the data (and optionally an NSError) for a failure.
|
||||
typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData * GTM_NULLABLE_TYPE data,
|
||||
typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData *_Nullable data,
|
||||
int64_t fullUploadLength,
|
||||
NSError * GTM_NULLABLE_TYPE error);
|
||||
NSError *_Nullable error);
|
||||
// Do not call the response with an NSData object with less data than the requested length unless
|
||||
// you are passing the fullUploadLength to the fetcher for the first time and it is the last chunk
|
||||
// of data in the file being uploaded.
|
||||
typedef void (^GTMSessionUploadFetcherDataProvider)(int64_t offset, int64_t length,
|
||||
GTMSessionUploadFetcherDataProviderResponse response);
|
||||
typedef void (^GTMSessionUploadFetcherDataProvider)(
|
||||
int64_t offset, int64_t length, GTMSessionUploadFetcherDataProviderResponse response);
|
||||
|
||||
// Block to be notified about the final status of the cancellation request started in stopFetching.
|
||||
//
|
||||
// |fetcher| will be the cancel request that was sent to the server, or nil if stopFetching is not
|
||||
// going to send a cancel request. If |fetcher| is provided, the other parameters correspond to the
|
||||
// completion handler of the cancellation request fetcher.
|
||||
typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
||||
GTMSessionFetcher * GTM_NULLABLE_TYPE fetcher,
|
||||
NSData * GTM_NULLABLE_TYPE data,
|
||||
NSError * GTM_NULLABLE_TYPE error);
|
||||
typedef void (^GTMSessionUploadFetcherCancellationHandler)(GTMSessionFetcher *_Nullable fetcher,
|
||||
NSData *_Nullable data,
|
||||
NSError *_Nullable error);
|
||||
|
||||
@interface GTMSessionUploadFetcher : GTMSessionFetcher
|
||||
|
||||
@ -100,37 +99,37 @@ typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
||||
+ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request
|
||||
uploadMIMEType:(NSString *)uploadMIMEType
|
||||
chunkSize:(int64_t)chunkSize
|
||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
|
||||
// Allows cellular access.
|
||||
+ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL
|
||||
+ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL
|
||||
uploadMIMEType:(NSString *)uploadMIMEType
|
||||
chunkSize:(int64_t)chunkSize
|
||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
|
||||
+ (instancetype)uploadFetcherWithLocation:(NSURL *GTM_NULLABLE_TYPE)uploadLocationURL
|
||||
+ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL
|
||||
uploadMIMEType:(NSString *)uploadMIMEType
|
||||
chunkSize:(int64_t)chunkSize
|
||||
allowsCellularAccess:(BOOL)allowsCellularAccess
|
||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||
|
||||
// Allows dataProviders for files of unknown length. Pass kGTMSessionUploadFetcherUnknownFileSize as
|
||||
// |fullLength| if the length is unknown.
|
||||
- (void)setUploadDataLength:(int64_t)fullLength
|
||||
provider:(GTM_NULLABLE GTMSessionUploadFetcherDataProvider)block;
|
||||
provider:(nullable GTMSessionUploadFetcherDataProvider)block;
|
||||
|
||||
+ (NSArray *)uploadFetchersForBackgroundSessions;
|
||||
+ (GTM_NULLABLE instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier;
|
||||
+ (nullable instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier;
|
||||
|
||||
- (void)pauseFetching;
|
||||
- (void)resumeFetching;
|
||||
- (BOOL)isPaused;
|
||||
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURL *uploadLocationURL;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSData *uploadData;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSURL *uploadFileURL;
|
||||
@property(atomic, strong, GTM_NULLABLE) NSFileHandle *uploadFileHandle;
|
||||
@property(atomic, copy, readonly, GTM_NULLABLE) GTMSessionUploadFetcherDataProvider uploadDataProvider;
|
||||
@property(atomic, strong, nullable) NSURL *uploadLocationURL;
|
||||
@property(atomic, strong, nullable) NSData *uploadData;
|
||||
@property(atomic, strong, nullable) NSURL *uploadFileURL;
|
||||
@property(atomic, strong, nullable) NSFileHandle *uploadFileHandle;
|
||||
@property(atomic, copy, readonly, nullable) GTMSessionUploadFetcherDataProvider uploadDataProvider;
|
||||
@property(atomic, copy) NSString *uploadMIMEType;
|
||||
@property(atomic, readonly, assign) int64_t chunkSize;
|
||||
@property(atomic, readonly, assign) int64_t currentOffset;
|
||||
@ -138,14 +137,14 @@ typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
||||
@property(atomic, readonly, assign) BOOL allowsCellularAccess;
|
||||
|
||||
// The fetcher for the current data chunk, if any
|
||||
@property(atomic, strong, GTM_NULLABLE) GTMSessionFetcher *chunkFetcher;
|
||||
@property(atomic, strong, nullable) GTMSessionFetcher *chunkFetcher;
|
||||
|
||||
// The active fetcher is the current chunk fetcher, or the upload fetcher itself
|
||||
// if no chunk fetcher has yet been created.
|
||||
@property(atomic, readonly) GTMSessionFetcher *activeFetcher;
|
||||
|
||||
// The last request made by an active fetcher. Useful for testing.
|
||||
@property(atomic, readonly, GTM_NULLABLE) NSURLRequest *lastChunkRequest;
|
||||
@property(atomic, readonly, nullable) NSURLRequest *lastChunkRequest;
|
||||
|
||||
// The status code from the most recently-completed fetch.
|
||||
@property(atomic, assign) NSInteger statusCode;
|
||||
@ -157,19 +156,18 @@ typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
||||
// Unlike other callbacks, since this is related specifically to the stopFetching flow it is not
|
||||
// cleared by stopFetching. It will instead clear itself after it is invoked or if the completion
|
||||
// has occured before stopFetching is called.
|
||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionUploadFetcherCancellationHandler
|
||||
cancellationHandler;
|
||||
@property(atomic, copy, nullable) GTMSessionUploadFetcherCancellationHandler cancellationHandler;
|
||||
|
||||
// Exposed for testing only.
|
||||
@property(atomic, readonly, GTM_NULLABLE) dispatch_queue_t delegateCallbackQueue;
|
||||
@property(atomic, readonly, GTM_NULLABLE) GTMSessionFetcherCompletionHandler delegateCompletionHandler;
|
||||
@property(atomic, readonly, nullable) dispatch_queue_t delegateCallbackQueue;
|
||||
@property(atomic, readonly, nullable) GTMSessionFetcherCompletionHandler delegateCompletionHandler;
|
||||
|
||||
@end
|
||||
|
||||
@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods)
|
||||
|
||||
@property(readonly, GTM_NULLABLE) GTMSessionUploadFetcher *parentUploadFetcher;
|
||||
@property(readonly, nullable) GTMSessionUploadFetcher *parentUploadFetcher;
|
||||
|
||||
@end
|
||||
|
||||
GTM_ASSUME_NONNULL_END
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
558
Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m
generated
558
Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m
generated
File diff suppressed because it is too large
Load Diff
22
Pods/GoogleSignIn/CHANGELOG.md
generated
22
Pods/GoogleSignIn/CHANGELOG.md
generated
@ -1,3 +1,25 @@
|
||||
# 2019-11-7 -- v5.0.2
|
||||
- Fixes the wrong error code being sent to `signIn:didSignInForUser:withError:` when the user
|
||||
cancels iOS's consent dialog during the sign-in flow.
|
||||
|
||||
# 2019-10-9 -- v5.0.1
|
||||
- Fixes an issue that the sign in flow cannot be correctly started on iOS 13.
|
||||
- The zip distribution requires Xcode 11 or above.
|
||||
|
||||
# 2019-8-14 -- v5.0.0
|
||||
- Changes to GIDSignIn
|
||||
- `uiDelegate` has been replaced with `presentingViewController`.
|
||||
- `hasAuthInKeychain` has been replaced with `hasPreviousSignIn`.
|
||||
- `signInSilently` has been replaced with `restorePreviousSignIn`.
|
||||
- Removed deprecated `kGIDSignInErrorCodeNoSignInHandlersInstalled` error code.
|
||||
- Changes to GIDAuthentication
|
||||
- Removed deprecated methods `getAccessTokenWithHandler:` and `refreshAccessTokenWithHandler:`.
|
||||
- Changes to GIDGoogleUser
|
||||
- Removed deprecated property `accessibleScopes`, use `grantedScopes` instead.
|
||||
- Adds dependencies on AppAuth and GTMAppAuth.
|
||||
- Removes the dependency on GoogleToolboxForMac.
|
||||
- Drops support for iOS 7.
|
||||
|
||||
# 2018-11-26 -- v4.4.0
|
||||
- Removes the dependency on GTM OAuth 2.
|
||||
|
||||
|
||||
Binary file not shown.
@ -13,60 +13,53 @@
|
||||
@protocol GTMFetcherAuthorizationProtocol;
|
||||
@class GIDAuthentication;
|
||||
|
||||
// @relates GIDAuthentication
|
||||
//
|
||||
// The callback block that takes a GIDAuthentication, or an error if attempt to refresh was
|
||||
// unsuccessful.
|
||||
/// The callback block that takes a `GIDAuthentication`, or an error if attempt
|
||||
/// to refresh was unsuccessful.
|
||||
typedef void (^GIDAuthenticationHandler)(GIDAuthentication *authentication, NSError *error);
|
||||
|
||||
// @relates GIDAuthentication
|
||||
//
|
||||
// The callback block that takes an access token, or an error if attempt to refresh was
|
||||
// unsuccessful.
|
||||
/// The callback block that takes an access token, or an error if attempt to refresh was
|
||||
/// unsuccessful.
|
||||
typedef void (^GIDAccessTokenHandler)(NSString *accessToken, NSError *error);
|
||||
|
||||
// This class represents the OAuth 2.0 entities needed for sign-in.
|
||||
@interface GIDAuthentication : NSObject <NSCoding>
|
||||
/// This class represents the OAuth 2.0 entities needed for sign-in.
|
||||
@interface GIDAuthentication : NSObject <NSSecureCoding>
|
||||
|
||||
// The client ID associated with the authentication.
|
||||
/// The client ID associated with the authentication.
|
||||
@property(nonatomic, readonly) NSString *clientID;
|
||||
|
||||
// The OAuth2 access token to access Google services.
|
||||
/// The OAuth2 access token to access Google services.
|
||||
@property(nonatomic, readonly) NSString *accessToken;
|
||||
|
||||
// The estimated expiration date of the access token.
|
||||
/// The estimated expiration date of the access token.
|
||||
@property(nonatomic, readonly) NSDate *accessTokenExpirationDate;
|
||||
|
||||
// The OAuth2 refresh token to exchange for new access tokens.
|
||||
/// The OAuth2 refresh token to exchange for new access tokens.
|
||||
@property(nonatomic, readonly) NSString *refreshToken;
|
||||
|
||||
// An OpenID Connect ID token that identifies the user. Send this token to your server to
|
||||
// authenticate the user there. For more information on this topic, see
|
||||
// https://developers.google.com/identity/sign-in/ios/backend-auth
|
||||
/// An OpenID Connect ID token that identifies the user. Send this token to your server to
|
||||
/// authenticate the user there. For more information on this topic, see
|
||||
/// https://developers.google.com/identity/sign-in/ios/backend-auth
|
||||
@property(nonatomic, readonly) NSString *idToken;
|
||||
|
||||
// The estimated expiration date of the ID token.
|
||||
/// The estimated expiration date of the ID token.
|
||||
@property(nonatomic, readonly) NSDate *idTokenExpirationDate;
|
||||
|
||||
// Gets a new authorizer for GTLService, GTMSessionFetcher, or GTMHTTPFetcher.
|
||||
/// Gets a new authorizer for `GTLService`, `GTMSessionFetcher`, or `GTMHTTPFetcher`.
|
||||
///
|
||||
/// @return A new authorizer
|
||||
- (id<GTMFetcherAuthorizationProtocol>)fetcherAuthorizer;
|
||||
|
||||
// Get a valid access token and a valid ID token, refreshing them first if they have expired or are
|
||||
// about to expire.
|
||||
/// Get a valid access token and a valid ID token, refreshing them first if they have expired or are
|
||||
/// about to expire.
|
||||
///
|
||||
/// @param handler A callback block that takes a `GIDAuthentication`, or an
|
||||
/// error if attempt to refresh was unsuccessful.
|
||||
- (void)getTokensWithHandler:(GIDAuthenticationHandler)handler;
|
||||
|
||||
// Refreshes the access token and the ID token using the refresh token.
|
||||
/// Refreshes the access token and the ID token using the refresh token.
|
||||
///
|
||||
/// @param handler A callback block that takes a `GIDAuthentication`, or an
|
||||
/// error if attempt to refresh was unsuccessful.
|
||||
- (void)refreshTokensWithHandler:(GIDAuthenticationHandler)handler;
|
||||
|
||||
// Gets the access token, which may be a new one from the refresh token if the original has already
|
||||
// expired or is about to expire. Deprecated: use |getTokensWithHandler:| to get access tokens
|
||||
// instead.
|
||||
- (void)getAccessTokenWithHandler:(GIDAccessTokenHandler)handler
|
||||
DEPRECATED_MSG_ATTRIBUTE("Use |getTokensWithHandler:| instead.");
|
||||
|
||||
// Refreshes the access token with the refresh token. Deprecated: Use |refreshTokensWithHandler:|
|
||||
// to refresh access tokens instead.
|
||||
- (void)refreshAccessTokenWithHandler:(GIDAccessTokenHandler)handler
|
||||
DEPRECATED_MSG_ATTRIBUTE("Use |refreshTokensWithHandler:| instead.");
|
||||
|
||||
@end
|
||||
|
||||
@ -13,31 +13,27 @@
|
||||
@class GIDAuthentication;
|
||||
@class GIDProfileData;
|
||||
|
||||
// This class represents a user account.
|
||||
@interface GIDGoogleUser : NSObject <NSCoding>
|
||||
/// This class represents a user account.
|
||||
@interface GIDGoogleUser : NSObject <NSSecureCoding>
|
||||
|
||||
// The Google user ID.
|
||||
/// The Google user ID.
|
||||
@property(nonatomic, readonly) NSString *userID;
|
||||
|
||||
// Representation of the Basic profile data. It is only available if |shouldFetchBasicProfile|
|
||||
// is set and either |signIn| or |signInSilently| has been completed successfully.
|
||||
/// Representation of the Basic profile data. It is only available if
|
||||
/// `GIDSignIn.shouldFetchBasicProfile` is set and either `-[GIDSignIn signIn]` or
|
||||
/// `-[GIDSignIn restorePreviousSignIn]` has been completed successfully.
|
||||
@property(nonatomic, readonly) GIDProfileData *profile;
|
||||
|
||||
// The authentication object for the user.
|
||||
/// The authentication object for the user.
|
||||
@property(nonatomic, readonly) GIDAuthentication *authentication;
|
||||
|
||||
// The API scopes requested by the app in an array of |NSString|s. Deprecated.
|
||||
// Use |grantedScopes| instead.
|
||||
@property(nonatomic, readonly) NSArray *accessibleScopes
|
||||
__attribute__((deprecated("Use grantedScopes instead.")));
|
||||
|
||||
// The API scopes granted to the app in an array of |NSString|s.
|
||||
/// The API scopes granted to the app in an array of `NSString`.
|
||||
@property(nonatomic, readonly) NSArray *grantedScopes;
|
||||
|
||||
// For Google Apps hosted accounts, the domain of the user.
|
||||
/// For Google Apps hosted accounts, the domain of the user.
|
||||
@property(nonatomic, readonly) NSString *hostedDomain;
|
||||
|
||||
// An OAuth2 authorization code for the home server.
|
||||
/// An OAuth2 authorization code for the home server.
|
||||
@property(nonatomic, readonly) NSString *serverAuthCode;
|
||||
|
||||
@end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user