[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:
|
PODS:
|
||||||
- Alamofire (4.7.3)
|
- 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):
|
- Crashlytics (3.8.6):
|
||||||
- Fabric (~> 1.6.3)
|
- Fabric (~> 1.6.3)
|
||||||
- DeltaCore (0.1):
|
- DeltaCore (0.1):
|
||||||
@ -16,30 +22,25 @@ PODS:
|
|||||||
- GoogleAPIClientForREST/Drive (1.3.11):
|
- GoogleAPIClientForREST/Drive (1.3.11):
|
||||||
- GoogleAPIClientForREST/Core
|
- GoogleAPIClientForREST/Core
|
||||||
- GTMSessionFetcher (>= 1.1.7)
|
- GTMSessionFetcher (>= 1.1.7)
|
||||||
- GoogleSignIn (4.4.0):
|
- GoogleSignIn (5.0.2):
|
||||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
|
- AppAuth (~> 1.2)
|
||||||
- "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)"
|
- GTMAppAuth (~> 1.0)
|
||||||
- GTMSessionFetcher/Core (~> 1.1)
|
- GTMSessionFetcher/Core (~> 1.1)
|
||||||
- GoogleToolboxForMac/DebugUtils (2.3.0):
|
- GTMAppAuth (1.3.1):
|
||||||
- GoogleToolboxForMac/Defines (= 2.3.0)
|
- AppAuth/Core (~> 1.6)
|
||||||
- GoogleToolboxForMac/Defines (2.3.0)
|
- GTMSessionFetcher/Core (< 3.0, >= 1.5)
|
||||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (2.3.0)":
|
- GTMSessionFetcher (1.7.2):
|
||||||
- GoogleToolboxForMac/DebugUtils (= 2.3.0)
|
- GTMSessionFetcher/Full (= 1.7.2)
|
||||||
- GoogleToolboxForMac/Defines (= 2.3.0)
|
- GTMSessionFetcher/Core (1.7.2)
|
||||||
- "GoogleToolboxForMac/NSString+URLArguments (= 2.3.0)"
|
- GTMSessionFetcher/Full (1.7.2):
|
||||||
- "GoogleToolboxForMac/NSString+URLArguments (2.3.0)"
|
- GTMSessionFetcher/Core (= 1.7.2)
|
||||||
- GTMSessionFetcher (1.5.0):
|
|
||||||
- GTMSessionFetcher/Full (= 1.5.0)
|
|
||||||
- GTMSessionFetcher/Core (1.5.0)
|
|
||||||
- GTMSessionFetcher/Full (1.5.0):
|
|
||||||
- GTMSessionFetcher/Core (= 1.5.0)
|
|
||||||
- Harmony (0.1):
|
- Harmony (0.1):
|
||||||
- Harmony/Harmony-Drive (= 0.1)
|
- Harmony/Harmony-Drive (= 0.1)
|
||||||
- Harmony/Harmony-Dropbox (= 0.1)
|
- Harmony/Harmony-Dropbox (= 0.1)
|
||||||
- Roxas
|
- Roxas
|
||||||
- Harmony/Harmony-Drive (0.1):
|
- Harmony/Harmony-Drive (0.1):
|
||||||
- GoogleAPIClientForREST/Drive (~> 1.3.0)
|
- GoogleAPIClientForREST/Drive (~> 1.3.0)
|
||||||
- GoogleSignIn (~> 4.4.0)
|
- GoogleSignIn (~> 5.0)
|
||||||
- Roxas
|
- Roxas
|
||||||
- Harmony/Harmony-Dropbox (0.1):
|
- Harmony/Harmony-Dropbox (0.1):
|
||||||
- Roxas
|
- Roxas
|
||||||
@ -90,11 +91,12 @@ DEPENDENCIES:
|
|||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- Alamofire
|
- Alamofire
|
||||||
|
- AppAuth
|
||||||
- Crashlytics
|
- Crashlytics
|
||||||
- Fabric
|
- Fabric
|
||||||
- GoogleAPIClientForREST
|
- GoogleAPIClientForREST
|
||||||
- GoogleSignIn
|
- GoogleSignIn
|
||||||
- GoogleToolboxForMac
|
- GTMAppAuth
|
||||||
- GTMSessionFetcher
|
- GTMSessionFetcher
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
- SMCalloutView
|
- SMCalloutView
|
||||||
@ -126,6 +128,7 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568
|
Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568
|
||||||
|
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
|
||||||
Crashlytics: e156f27e43abaa331f9b7afed091bda37e1052cc
|
Crashlytics: e156f27e43abaa331f9b7afed091bda37e1052cc
|
||||||
DeltaCore: 6a430005ea397fcd5b40b964effe41ac69cc9037
|
DeltaCore: 6a430005ea397fcd5b40b964effe41ac69cc9037
|
||||||
DSDeltaCore: d22a7cfbbe70f063b8c72dec9d1bcd2c59e14893
|
DSDeltaCore: d22a7cfbbe70f063b8c72dec9d1bcd2c59e14893
|
||||||
@ -133,10 +136,10 @@ SPEC CHECKSUMS:
|
|||||||
GBADeltaCore: c2f7ce5e5616ed63d2b99c9ba9a7e020f2263248
|
GBADeltaCore: c2f7ce5e5616ed63d2b99c9ba9a7e020f2263248
|
||||||
GBCDeltaCore: 27f09a1c88a4ac832aa549fbe34aaf277251b6b8
|
GBCDeltaCore: 27f09a1c88a4ac832aa549fbe34aaf277251b6b8
|
||||||
GoogleAPIClientForREST: 0f19a8280dfe6471f76016645d26eb5dae305101
|
GoogleAPIClientForREST: 0f19a8280dfe6471f76016645d26eb5dae305101
|
||||||
GoogleSignIn: 7ff245e1a7b26d379099d3243a562f5747e23d39
|
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
||||||
GoogleToolboxForMac: 1350d40e86a76f7863928d63bcb0b89c84c521c5
|
GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
|
||||||
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
|
GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba
|
||||||
Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96
|
Harmony: 5fdc51d0a4f2ce7dcd4439becbbdda1fac4c9e3f
|
||||||
MelonDSDeltaCore: 46193f4fd88e4e18e4a5c841b1ae02dc46d1daa6
|
MelonDSDeltaCore: 46193f4fd88e4e18e4a5c841b1ae02dc46d1daa6
|
||||||
N64DeltaCore: 4eeb468746722952bcd5467ecb9ebe7df070f53a
|
N64DeltaCore: 4eeb468746722952bcd5467ecb9ebe7df070f53a
|
||||||
NESDeltaCore: ffae3bba878fc505bac0914150a695ede7bc9550
|
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>
|
**Project site** <https://github.com/google/gtm-session-fetcher><br>
|
||||||
**Discussion group** <http://groups.google.com/group/google-toolbox-for-mac>
|
**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
|
`GTMSessionFetcher` makes it easy for Cocoa applications to perform http
|
||||||
operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its
|
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>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
// These will be removed in the near future, folks should move off of them.
|
||||||
#ifndef GTM_NONNULL
|
#ifndef GTM_NONNULL
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(nonnull)
|
#if __has_attribute(nonnull)
|
||||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Avoid multiple declaration of this class.
|
// Avoid multiple declaration of this class.
|
||||||
@ -45,7 +46,7 @@
|
|||||||
|
|
||||||
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
||||||
|
|
||||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray GTM_NONNULL((1));
|
+ (nonnull instancetype)streamWithArray:(nonnull NSArray *)dataArray;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
10
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.m
generated
10
Pods/GTMSessionFetcher/Source/GTMGatherInputStream.m
generated
@ -27,11 +27,11 @@
|
|||||||
id<NSStreamDelegate> __weak _delegate; // Stream delegate, defaults to self.
|
id<NSStreamDelegate> __weak _delegate; // Stream delegate, defaults to self.
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray {
|
+ (instancetype)streamWithArray:(NSArray *)dataArray {
|
||||||
return [(GTMGatherInputStream *)[self alloc] initWithArray:dataArray];
|
return [[self alloc] initWithDataArray:dataArray];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithArray:(NSArray *)dataArray {
|
- (instancetype)initWithDataArray:(NSArray *)dataArray {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_dataArray = dataArray;
|
_dataArray = dataArray;
|
||||||
@ -108,7 +108,7 @@
|
|||||||
NSUInteger dataBytesLeft = dataLen - (NSUInteger)_dataOffset;
|
NSUInteger dataBytesLeft = dataLen - (NSUInteger)_dataOffset;
|
||||||
|
|
||||||
NSUInteger bytesToCopy = MIN(bytesRemaining, dataBytesLeft);
|
NSUInteger bytesToCopy = MIN(bytesRemaining, dataBytesLeft);
|
||||||
NSRange range = NSMakeRange((NSUInteger) _dataOffset, bytesToCopy);
|
NSRange range = NSMakeRange((NSUInteger)_dataOffset, bytesToCopy);
|
||||||
|
|
||||||
[data getBytes:(buffer + bytesRead) range:range];
|
[data getBytes:(buffer + bytesRead) range:range];
|
||||||
|
|
||||||
@ -168,7 +168,7 @@
|
|||||||
_arrayIndex = 0;
|
_arrayIndex = 0;
|
||||||
_dataOffset = absoluteOffset;
|
_dataOffset = absoluteOffset;
|
||||||
for (NSData *data in _dataArray) {
|
for (NSData *data in _dataArray) {
|
||||||
long long dataLen = (long long) data.length;
|
long long dataLen = (long long)data.length;
|
||||||
if (dataLen > _dataOffset) {
|
if (dataLen > _dataOffset) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
108
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.h
generated
108
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.h
generated
@ -22,34 +22,33 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
// These will be removed in the near future, folks should move off of them.
|
||||||
#ifndef GTM_NONNULL
|
#ifndef GTM_NONNULL
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(nonnull)
|
#if __has_attribute(nonnull)
|
||||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GTM_DECLARE_GENERICS
|
#ifndef GTM_DECLARE_GENERICS
|
||||||
#if __has_feature(objc_generics)
|
#if __has_feature(objc_generics)
|
||||||
#define GTM_DECLARE_GENERICS 1
|
#define GTM_DECLARE_GENERICS 1
|
||||||
#else
|
#else
|
||||||
#define GTM_DECLARE_GENERICS 0
|
#define GTM_DECLARE_GENERICS 0
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GTM_NSArrayOf
|
#ifndef GTM_NSArrayOf
|
||||||
#if GTM_DECLARE_GENERICS
|
#if GTM_DECLARE_GENERICS
|
||||||
#define GTM_NSArrayOf(value) NSArray<value>
|
#define GTM_NSArrayOf(value) NSArray<value>
|
||||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||||
#else
|
#else
|
||||||
#define GTM_NSArrayOf(value) NSArray
|
#define GTM_NSArrayOf(value) NSArray
|
||||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||||
#endif // GTM_DECLARE_GENERICS
|
#endif // GTM_DECLARE_GENERICS
|
||||||
#endif // GTM_NSArrayOf
|
#endif // GTM_NSArrayOf
|
||||||
|
|
||||||
|
|
||||||
@ -58,12 +57,13 @@
|
|||||||
// +[GTMMIMEDocument MIMEPartsWithBoundary:data:] returns an array of these.
|
// +[GTMMIMEDocument MIMEPartsWithBoundary:data:] returns an array of these.
|
||||||
@interface GTMMIMEDocumentPart : NSObject
|
@interface GTMMIMEDocumentPart : NSObject
|
||||||
|
|
||||||
@property(nonatomic, readonly) GTM_NSDictionaryOf(NSString *, NSString *) *headers;
|
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *headers;
|
||||||
@property(nonatomic, readonly) NSData *headerData;
|
@property(nonatomic, readonly, nonnull) NSData *headerData;
|
||||||
@property(nonatomic, readonly) NSData *body;
|
@property(nonatomic, readonly, nonnull) NSData *body;
|
||||||
@property(nonatomic, readonly) NSUInteger length;
|
@property(nonatomic, readonly) NSUInteger length;
|
||||||
|
|
||||||
+ (instancetype)partWithHeaders:(NSDictionary *)headers body:(NSData *)body;
|
+ (nonnull instancetype)partWithHeaders:(nullable NSDictionary *)headers
|
||||||
|
body:(nonnull NSData *)body;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -73,24 +73,24 @@
|
|||||||
//
|
//
|
||||||
// When creating a MIME document from parts, this is typically calculated
|
// When creating a MIME document from parts, this is typically calculated
|
||||||
// automatically after all parts have been added.
|
// 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
|
#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.
|
// Adds a new part to this mime document with the given headers and body.
|
||||||
// The headers keys and values should be NSStrings.
|
// The headers keys and values should be NSStrings.
|
||||||
// Adding a part may cause the boundary string to change.
|
// Adding a part may cause the boundary string to change.
|
||||||
- (void)addPartWithHeaders:(GTM_NSDictionaryOf(NSString *, NSString *) *)headers
|
- (void)addPartWithHeaders:(nonnull NSDictionary<NSString *, NSString *> *)headers
|
||||||
body:(NSData *)body GTM_NONNULL((1,2));
|
body:(nonnull NSData *)body;
|
||||||
|
|
||||||
// An inputstream that can be used to efficiently read the contents of the MIME document.
|
// 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.
|
// Any parameter may be null if the result is not wanted.
|
||||||
- (void)generateInputStream:(NSInputStream **)outStream
|
- (void)generateInputStream:(NSInputStream *_Nullable *_Nullable)outStream
|
||||||
length:(unsigned long long *)outLength
|
length:(unsigned long long *_Nullable)outLength
|
||||||
boundary:(NSString **)outBoundary;
|
boundary:(NSString *_Nullable *_Nullable)outBoundary;
|
||||||
|
|
||||||
// A dispatch_data_t with the contents of the MIME document.
|
// A dispatch_data_t with the contents of the MIME document.
|
||||||
//
|
//
|
||||||
@ -98,12 +98,12 @@
|
|||||||
// may be cast directly to NSData *.
|
// may be cast directly to NSData *.
|
||||||
//
|
//
|
||||||
// Any parameter may be null if the result is not wanted.
|
// Any parameter may be null if the result is not wanted.
|
||||||
- (void)generateDispatchData:(dispatch_data_t *)outDispatchData
|
- (void)generateDispatchData:(dispatch_data_t _Nullable *_Nullable)outDispatchData
|
||||||
length:(unsigned long long *)outLength
|
length:(unsigned long long *_Nullable)outLength
|
||||||
boundary:(NSString **)outBoundary;
|
boundary:(NSString *_Nullable *_Nullable)outBoundary;
|
||||||
|
|
||||||
// Utility method for making a header section, including trailing newlines.
|
// 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
|
#pragma mark - Methods for Parsing a MIME Document
|
||||||
|
|
||||||
@ -111,8 +111,14 @@
|
|||||||
//
|
//
|
||||||
// Returns an array of GTMMIMEDocumentParts. Returns nil if no part can
|
// Returns an array of GTMMIMEDocumentParts. Returns nil if no part can
|
||||||
// be found.
|
// 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
|
// Utility method for efficiently searching possibly discontiguous NSData
|
||||||
// for occurrences of target byte. This method does not "flatten" an 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
|
// The byte offsets of non-overlapping occurrences of the target are returned as
|
||||||
// NSNumbers in the array.
|
// NSNumbers in the array.
|
||||||
+ (void)searchData:(NSData *)data
|
+ (void)searchData:(nonnull NSData *)data
|
||||||
targetBytes:(const void *)targetBytes
|
targetBytes:(const void *_Nonnull)targetBytes
|
||||||
targetLength:(NSUInteger)targetLength
|
targetLength:(NSUInteger)targetLength
|
||||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets;
|
foundOffsets:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundOffsets;
|
||||||
|
|
||||||
// Utility method to parse header bytes into an NSDictionary.
|
// 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 ------
|
// ------ UNIT TESTING ONLY BELOW ------
|
||||||
|
|
||||||
// Internal methods, exposed for unit testing only.
|
// Internal methods, exposed for unit testing only.
|
||||||
- (void)seedRandomWith:(u_int32_t)seed;
|
- (void)seedRandomWith:(u_int32_t)seed;
|
||||||
|
|
||||||
+ (NSUInteger)findBytesWithNeedle:(const unsigned char *)needle
|
+ (NSUInteger)findBytesWithNeedle:(const unsigned char *_Nonnull)needle
|
||||||
needleLength:(NSUInteger)needleLength
|
needleLength:(NSUInteger)needleLength
|
||||||
haystack:(const unsigned char *)haystack
|
haystack:(const unsigned char *_Nonnull)haystack
|
||||||
haystackLength:(NSUInteger)haystackLength
|
haystackLength:(NSUInteger)haystackLength
|
||||||
foundOffset:(NSUInteger *)foundOffset;
|
foundOffset:(NSUInteger *_Nonnull)foundOffset;
|
||||||
|
|
||||||
+ (void)searchData:(NSData *)data
|
+ (void)searchData:(nonnull NSData *)data
|
||||||
targetBytes:(const void *)targetBytes
|
targetBytes:(const void *_Nonnull)targetBytes
|
||||||
targetLength:(NSUInteger)targetLength
|
targetLength:(NSUInteger)targetLength
|
||||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets
|
foundOffsets:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundOffsets
|
||||||
foundBlockNumbers:(GTM_NSArrayOf(NSNumber *) **)outFoundBlockNumbers;
|
foundBlockNumbers:(NSArray<NSNumber *> *_Nullable *_Nonnull)outFoundBlockNumbers;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
103
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.m
generated
103
Pods/GTMSessionFetcher/Source/GTMMIMEDocument.m
generated
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
@interface GTMGatherInputStream : NSInputStream <NSStreamDelegate>
|
||||||
|
|
||||||
+ (NSInputStream *)streamWithArray:(NSArray *)dataArray GTM_NONNULL((1));
|
+ (nonnull instancetype)streamWithArray:(nonnull NSArray *)dataArray;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
#endif // GTM_GATHERINPUTSTREAM_DECLARED
|
#endif // GTM_GATHERINPUTSTREAM_DECLARED
|
||||||
@ -55,9 +55,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
NSData *_bodyData;
|
NSData *_bodyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize headers = _headers,
|
@synthesize headers = _headers, headerData = _headerData, body = _bodyData;
|
||||||
headerData = _headerData,
|
|
||||||
body = _bodyData;
|
|
||||||
|
|
||||||
@dynamic length;
|
@dynamic length;
|
||||||
|
|
||||||
@ -102,16 +100,16 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description {
|
- (NSString *)description {
|
||||||
return [NSString stringWithFormat:@"%@ %p (headers %lu keys, body %lu bytes)",
|
return [NSString stringWithFormat:@"%@ %p (headers %lu keys, body %lu bytes)", [self class], self,
|
||||||
[self class], self, (unsigned long)_headers.count,
|
(unsigned long)_headers.count, (unsigned long)_bodyData.length];
|
||||||
(unsigned long)_bodyData.length];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isEqual:(GTMMIMEDocumentPart *)other {
|
- (BOOL)isEqual:(id)other {
|
||||||
if (self == other) return YES;
|
if (self == other) return YES;
|
||||||
if (![other isKindOfClass:[GTMMIMEDocumentPart class]]) return NO;
|
if (![other isKindOfClass:[GTMMIMEDocumentPart class]]) return NO;
|
||||||
return ((_bodyData == other->_bodyData || [_bodyData isEqual:other->_bodyData])
|
GTMMIMEDocumentPart *otherPart = (GTMMIMEDocumentPart *)other;
|
||||||
&& (_headers == other->_headers || [_headers isEqual:other->_headers]));
|
return ((_bodyData == otherPart->_bodyData || [_bodyData isEqual:otherPart->_bodyData]) &&
|
||||||
|
(_headers == otherPart->_headers || [_headers isEqual:otherPart->_headers]));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)hash {
|
- (NSUInteger)hash {
|
||||||
@ -140,8 +138,8 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description {
|
- (NSString *)description {
|
||||||
return [NSString stringWithFormat:@"%@ %p (%lu parts)",
|
return [NSString
|
||||||
[self class], self, (unsigned long)_parts.count];
|
stringWithFormat:@"%@ %p (%lu parts)", [self class], self, (unsigned long)_parts.count];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Joining Parts
|
#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.
|
const int maxTries = 10; // Arbitrarily chosen maximum attempts.
|
||||||
for (int tries = 0; tries < maxTries; ++tries) {
|
for (int tries = 0; tries < maxTries; ++tries) {
|
||||||
|
|
||||||
NSData *data = [_boundary dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *data = [_boundary dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
const void *dataBytes = data.bytes;
|
const void *dataBytes = data.bytes;
|
||||||
NSUInteger dataLen = data.length;
|
NSUInteger dataLen = data.length;
|
||||||
@ -219,7 +216,6 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
- (void)generateDataArray:(NSMutableArray *)dataArray
|
- (void)generateDataArray:(NSMutableArray *)dataArray
|
||||||
length:(unsigned long long *)outLength
|
length:(unsigned long long *)outLength
|
||||||
boundary:(NSString **)outBoundary {
|
boundary:(NSString **)outBoundary {
|
||||||
|
|
||||||
// The input stream is of the form:
|
// The input stream is of the form:
|
||||||
// --boundary
|
// --boundary
|
||||||
// [part_1_headers]
|
// [part_1_headers]
|
||||||
@ -260,9 +256,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
length:(unsigned long long *)outLength
|
length:(unsigned long long *)outLength
|
||||||
boundary:(NSString **)outBoundary {
|
boundary:(NSString **)outBoundary {
|
||||||
NSMutableArray *dataArray = outStream ? [NSMutableArray array] : nil;
|
NSMutableArray *dataArray = outStream ? [NSMutableArray array] : nil;
|
||||||
[self generateDataArray:dataArray
|
[self generateDataArray:dataArray length:outLength boundary:outBoundary];
|
||||||
length:outLength
|
|
||||||
boundary:outBoundary];
|
|
||||||
|
|
||||||
if (outStream) {
|
if (outStream) {
|
||||||
Class streamClass = NSClassFromString(@"GTMGatherInputStream");
|
Class streamClass = NSClassFromString(@"GTMGatherInputStream");
|
||||||
@ -276,9 +270,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
length:(unsigned long long *)outLength
|
length:(unsigned long long *)outLength
|
||||||
boundary:(NSString **)outBoundary {
|
boundary:(NSString **)outBoundary {
|
||||||
NSMutableArray *dataArray = outDispatchData ? [NSMutableArray array] : nil;
|
NSMutableArray *dataArray = outDispatchData ? [NSMutableArray array] : nil;
|
||||||
[self generateDataArray:dataArray
|
[self generateDataArray:dataArray length:outLength boundary:outBoundary];
|
||||||
length:outLength
|
|
||||||
boundary:outBoundary];
|
|
||||||
|
|
||||||
if (outDispatchData) {
|
if (outDispatchData) {
|
||||||
// Create an empty data accumulator.
|
// Create an empty data accumulator.
|
||||||
@ -308,7 +300,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
|
|
||||||
+ (NSData *)dataWithHeaders:(NSDictionary *)headers {
|
+ (NSData *)dataWithHeaders:(NSDictionary *)headers {
|
||||||
// Generate the header data by coalescing the dictionary as lines of "key: value\r\n".
|
// 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.
|
// Sort the header keys so we have a deterministic order for unit testing.
|
||||||
SEL sortSel = @selector(caseInsensitiveCompare:);
|
SEL sortSel = @selector(caseInsensitiveCompare:);
|
||||||
@ -340,8 +332,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
|
|
||||||
#pragma mark - Separating Parts
|
#pragma mark - Separating Parts
|
||||||
|
|
||||||
+ (NSArray *)MIMEPartsWithBoundary:(NSString *)boundary
|
+ (NSArray *)MIMEPartsWithBoundary:(NSString *)boundary data:(NSData *)fullDocumentData {
|
||||||
data:(NSData *)fullDocumentData {
|
|
||||||
// In MIME documents, the boundary is preceded by CRLF and two dashes, and followed
|
// In MIME documents, the boundary is preceded by CRLF and two dashes, and followed
|
||||||
// at the end by two dashes.
|
// at the end by two dashes.
|
||||||
NSData *boundaryData = [boundary dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *boundaryData = [boundary dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
@ -367,9 +358,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
} else {
|
} else {
|
||||||
// A no-op self invocation on fullDocumentData will keep it retained until the block is invoked.
|
// 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);
|
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||||
dataWrapper = dispatch_data_create(fullDocumentData.bytes,
|
dataWrapper = dispatch_data_create(fullDocumentData.bytes, fullDocumentData.length, bgQueue, ^{
|
||||||
fullDocumentData.length,
|
[fullDocumentData self];
|
||||||
bgQueue, ^{ [fullDocumentData self]; });
|
});
|
||||||
}
|
}
|
||||||
NSMutableArray *parts;
|
NSMutableArray *parts;
|
||||||
NSInteger previousBoundaryOffset = -1;
|
NSInteger previousBoundaryOffset = -1;
|
||||||
@ -394,15 +385,13 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
if (previousPartDataLength < 2) {
|
if (previousPartDataLength < 2) {
|
||||||
// The preceding part was too short to be useful.
|
// The preceding part was too short to be useful.
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
NSLog(@"MIME part %ld has %ld bytes", (long)partCounter - 1,
|
NSLog(@"MIME part %ld has %ld bytes", (long)partCounter - 1, (long)previousPartDataLength);
|
||||||
(long)previousPartDataLength);
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (!parts) parts = [NSMutableArray array];
|
if (!parts) parts = [NSMutableArray array];
|
||||||
|
|
||||||
dispatch_data_t partData =
|
dispatch_data_t partData = dispatch_data_create_subrange(
|
||||||
dispatch_data_create_subrange(dataWrapper,
|
dataWrapper, (size_t)previousPartDataStartOffset, (size_t)previousPartDataLength);
|
||||||
(size_t)previousPartDataStartOffset, (size_t)previousPartDataLength);
|
|
||||||
// Scan the part data for the separator between headers and body. After the CRLF,
|
// 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.
|
// 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.
|
// and map that two-byte subrange.
|
||||||
const void *partDataBuffer;
|
const void *partDataBuffer;
|
||||||
size_t partDataBufferSize;
|
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_t mappedPartData NS_VALID_UNTIL_END_OF_SCOPE =
|
||||||
dispatch_data_create_map(partData, &partDataBuffer, &partDataBufferSize);
|
dispatch_data_create_map(partData, &partDataBuffer, &partDataBufferSize);
|
||||||
|
#pragma clang diagnostic pop
|
||||||
dispatch_data_t bodyData;
|
dispatch_data_t bodyData;
|
||||||
NSDictionary *headers;
|
NSDictionary *headers;
|
||||||
BOOL hasAnotherCRLF = (((char *)partDataBuffer)[0] == '\r'
|
BOOL hasAnotherCRLF =
|
||||||
&& ((char *)partDataBuffer)[1] == '\n');
|
(((char *)partDataBuffer)[0] == '\r' && ((char *)partDataBuffer)[1] == '\n');
|
||||||
mappedPartData = nil;
|
mappedPartData = nil;
|
||||||
|
|
||||||
if (hasAnotherCRLF) {
|
if (hasAnotherCRLF) {
|
||||||
@ -442,14 +437,18 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
dispatch_data_create_subrange(partData, 0, (size_t)headerSeparatorOffset);
|
dispatch_data_create_subrange(partData, 0, (size_t)headerSeparatorOffset);
|
||||||
headers = [self headersWithData:(NSData *)headerData];
|
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)));
|
(size_t)(previousPartDataLength - (headerSeparatorOffset + 4)));
|
||||||
|
|
||||||
numberOfPartsWithHeaders++;
|
numberOfPartsWithHeaders++;
|
||||||
} // crlfOffsets.count == 0
|
} // crlfOffsets.count == 0
|
||||||
} // hasAnotherCRLF
|
} // hasAnotherCRLF
|
||||||
GTMMIMEDocumentPart *part = [GTMMIMEDocumentPart partWithHeaders:headers
|
|
||||||
body:(NSData *)bodyData];
|
// 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];
|
[parts addObject:part];
|
||||||
} // previousPartDataLength < 2
|
} // previousPartDataLength < 2
|
||||||
previousBoundaryOffset = currentBoundaryOffset.integerValue;
|
previousBoundaryOffset = currentBoundaryOffset.integerValue;
|
||||||
@ -461,10 +460,7 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
NSUInteger length = fullDocumentData.length;
|
NSUInteger length = fullDocumentData.length;
|
||||||
if (length > 20) { // Reasonably long.
|
if (length > 20) { // Reasonably long.
|
||||||
NSMutableArray *foundCRLFs;
|
NSMutableArray *foundCRLFs;
|
||||||
[self searchData:fullDocumentData
|
[self searchData:fullDocumentData targetBytes:"\r\n" targetLength:2 foundOffsets:&foundCRLFs];
|
||||||
targetBytes:"\r\n"
|
|
||||||
targetLength:2
|
|
||||||
foundOffsets:&foundCRLFs];
|
|
||||||
if (foundCRLFs.count == 0) {
|
if (foundCRLFs.count == 0) {
|
||||||
// Parts were logged above (due to lacking header separators.)
|
// Parts were logged above (due to lacking header separators.)
|
||||||
NSLog(@"Warning: MIME document lacks any headers (may have wrong line endings)");
|
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
|
+ (void)searchData:(NSData *)data
|
||||||
targetBytes:(const void *)targetBytes
|
targetBytes:(const void *)targetBytes
|
||||||
targetLength:(NSUInteger)targetLength
|
targetLength:(NSUInteger)targetLength
|
||||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets {
|
foundOffsets:(NSArray<NSNumber *> **)outFoundOffsets {
|
||||||
NSMutableArray *foundOffsets = [NSMutableArray array];
|
NSMutableArray *foundOffsets = [NSMutableArray array];
|
||||||
SearchDataForBytes(data, targetBytes, targetLength, foundOffsets, NULL);
|
SearchDataForBytes(data, targetBytes, targetLength, foundOffsets, NULL);
|
||||||
*outFoundOffsets = foundOffsets;
|
*outFoundOffsets = foundOffsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This version of searchData: also returns the block numbers (0-based) where the
|
// 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
|
// target was found, used for testing that the supplied dispatch_data buffer
|
||||||
// has not been flattened.
|
// has not been flattened.
|
||||||
+ (void)searchData:(NSData *)data
|
+ (void)searchData:(NSData *)data
|
||||||
targetBytes:(const void *)targetBytes
|
targetBytes:(const void *)targetBytes
|
||||||
targetLength:(NSUInteger)targetLength
|
targetLength:(NSUInteger)targetLength
|
||||||
foundOffsets:(GTM_NSArrayOf(NSNumber *) **)outFoundOffsets
|
foundOffsets:(NSArray<NSNumber *> **)outFoundOffsets
|
||||||
foundBlockNumbers:(GTM_NSArrayOf(NSNumber *) **)outFoundBlockNumbers {
|
foundBlockNumbers:(NSArray<NSNumber *> **)outFoundBlockNumbers {
|
||||||
NSMutableArray *foundOffsets = [NSMutableArray array];
|
NSMutableArray *foundOffsets = [NSMutableArray array];
|
||||||
NSMutableArray *foundBlockNumbers = [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 priorPartialMatchStartingBlockNumber = -1;
|
||||||
__block NSInteger blockNumber = -1;
|
__block NSInteger blockNumber = -1;
|
||||||
|
|
||||||
[data enumerateByteRangesUsingBlock:^(const void *bytes,
|
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
|
||||||
NSRange byteRange,
|
|
||||||
BOOL *stop) {
|
|
||||||
// Search for the first character in the current range.
|
// Search for the first character in the current range.
|
||||||
const void *ptr = bytes;
|
const void *ptr = bytes;
|
||||||
NSInteger remainingInCurrentRange = (NSInteger)byteRange.length;
|
NSInteger remainingInCurrentRange = (NSInteger)byteRange.length;
|
||||||
@ -524,9 +517,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
if (priorPartialMatchAmount > 0) {
|
if (priorPartialMatchAmount > 0) {
|
||||||
NSUInteger amountRemainingToBeMatched = targetLength - priorPartialMatchAmount;
|
NSUInteger amountRemainingToBeMatched = targetLength - priorPartialMatchAmount;
|
||||||
NSUInteger remainingFoundOffset;
|
NSUInteger remainingFoundOffset;
|
||||||
NSUInteger amountMatched = FindBytes(targetBytes + priorPartialMatchAmount,
|
NSUInteger amountMatched =
|
||||||
amountRemainingToBeMatched,
|
FindBytes(targetBytes + priorPartialMatchAmount, amountRemainingToBeMatched, ptr,
|
||||||
ptr, (NSUInteger)remainingInCurrentRange, &remainingFoundOffset);
|
(NSUInteger)remainingInCurrentRange, &remainingFoundOffset);
|
||||||
if (amountMatched == 0 || remainingFoundOffset > 0) {
|
if (amountMatched == 0 || remainingFoundOffset > 0) {
|
||||||
// No match of the rest of the prior partial match in this range.
|
// No match of the rest of the prior partial match in this range.
|
||||||
} else if (amountMatched < amountRemainingToBeMatched) {
|
} else if (amountMatched < amountRemainingToBeMatched) {
|
||||||
@ -589,9 +582,9 @@ static void SearchDataForBytes(NSData *data, const void *targetBytes, NSUInteger
|
|||||||
NSCharacterSet *newlineCharacters = [NSCharacterSet newlineCharacterSet];
|
NSCharacterSet *newlineCharacters = [NSCharacterSet newlineCharacterSet];
|
||||||
NSString *key;
|
NSString *key;
|
||||||
NSString *value;
|
NSString *value;
|
||||||
while ([scanner scanUpToString:@":" intoString:&key]
|
while ([scanner scanUpToString:@":" intoString:&key] &&
|
||||||
&& [scanner scanString:@":" intoString:NULL]
|
[scanner scanString:@":" intoString:NULL] &&
|
||||||
&& [scanner scanUpToCharactersFromSet:newlineCharacters intoString:&value]) {
|
[scanner scanUpToCharactersFromSet:newlineCharacters intoString:&value]) {
|
||||||
[headers setObject:value forKey:key];
|
[headers setObject:value forKey:key];
|
||||||
// Discard the trailing newline.
|
// Discard the trailing newline.
|
||||||
[scanner scanCharactersFromSet:newlineCharacters intoString:NULL];
|
[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
|
// If the result is less than needleLen, then the beginning of the needle
|
||||||
// was found at the end of the haystack.
|
// was found at the end of the haystack.
|
||||||
static NSUInteger FindBytes(const unsigned char* needle, NSUInteger needleLen,
|
static NSUInteger FindBytes(const unsigned char *needle, NSUInteger needleLen,
|
||||||
const unsigned char* haystack, NSUInteger haystackLen,
|
const unsigned char *haystack, NSUInteger haystackLen,
|
||||||
NSUInteger *foundOffset) {
|
NSUInteger *foundOffset) {
|
||||||
const unsigned char *ptr = haystack;
|
const unsigned char *ptr = haystack;
|
||||||
NSInteger remain = (NSInteger)haystackLen;
|
NSInteger remain = (NSInteger)haystackLen;
|
||||||
|
|||||||
@ -15,24 +15,26 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
// These will be removed in the near future, folks should move off of them.
|
||||||
#ifndef GTM_NONNULL
|
#ifndef GTM_NONNULL
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(nonnull)
|
#if __has_attribute(nonnull)
|
||||||
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
#define GTM_NONNULL(x) __attribute__((nonnull x))
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define GTM_NONNULL(x)
|
#define GTM_NONNULL(x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface GTMReadMonitorInputStream : NSInputStream <NSStreamDelegate>
|
@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:
|
// The read monitor selector is called when bytes have been read. It should have this signature:
|
||||||
//
|
//
|
||||||
@ -41,9 +43,11 @@
|
|||||||
// length:(int64_t)length;
|
// length:(int64_t)length;
|
||||||
|
|
||||||
@property(atomic, weak) id readDelegate;
|
@property(atomic, weak) id readDelegate;
|
||||||
@property(atomic, assign) SEL readSelector;
|
@property(atomic) SEL readSelector;
|
||||||
|
|
||||||
// Modes for invoking callbacks, when necessary.
|
// Modes for invoking callbacks, when necessary.
|
||||||
@property(atomic, strong) NSArray *runLoopModes;
|
@property(atomic, copy, nullable) NSArray *runLoopModes;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@ -26,7 +26,6 @@
|
|||||||
NSArray *_runLoopModes; // Modes for calling callbacks, when necessary.
|
NSArray *_runLoopModes; // Modes for calling callbacks, when necessary.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@synthesize readDelegate = _readDelegate;
|
@synthesize readDelegate = _readDelegate;
|
||||||
@synthesize readSelector = _readSelector;
|
@synthesize readSelector = _readSelector;
|
||||||
@synthesize runLoopModes = _runLoopModes;
|
@synthesize runLoopModes = _runLoopModes;
|
||||||
@ -38,7 +37,7 @@
|
|||||||
return [NSInputStream methodSignatureForSelector:selector];
|
return [NSInputStream methodSignatureForSelector:selector];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)forwardInvocation:(NSInvocation*)invocation {
|
+ (void)forwardInvocation:(NSInvocation *)invocation {
|
||||||
[invocation invokeWithTarget:[NSInputStream class]];
|
[invocation invokeWithTarget:[NSInputStream class]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,11 +45,11 @@
|
|||||||
return [_inputStream respondsToSelector:selector];
|
return [_inputStream respondsToSelector:selector];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
|
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
|
||||||
return [_inputStream methodSignatureForSelector:selector];
|
return [_inputStream methodSignatureForSelector:selector];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)forwardInvocation:(NSInvocation*)invocation {
|
- (void)forwardInvocation:(NSInvocation *)invocation {
|
||||||
[invocation invokeWithTarget:_inputStream];
|
[invocation invokeWithTarget:_inputStream];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,10 +102,7 @@
|
|||||||
waitUntilDone:NO
|
waitUntilDone:NO
|
||||||
modes:_runLoopModes];
|
modes:_runLoopModes];
|
||||||
} else {
|
} else {
|
||||||
[self performSelector:sel
|
[self performSelector:sel onThread:_thread withObject:data waitUntilDone:NO];
|
||||||
onThread:_thread
|
|
||||||
withObject:data
|
|
||||||
waitUntilDone:NO];
|
|
||||||
}
|
}
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
@ -155,11 +151,11 @@
|
|||||||
[_inputStream close];
|
[_inputStream close];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)delegate {
|
- (id<NSStreamDelegate>)delegate {
|
||||||
return [_inputStream delegate];
|
return [_inputStream delegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDelegate:(id)delegate {
|
- (void)setDelegate:(id<NSStreamDelegate>)delegate {
|
||||||
[_inputStream setDelegate:delegate];
|
[_inputStream setDelegate:delegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
534
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
generated
534
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
generated
@ -136,6 +136,8 @@
|
|||||||
// Alternative HTTP methods, like PUT, and custom headers can be specified by
|
// Alternative HTTP methods, like PUT, and custom headers can be specified by
|
||||||
// creating the fetcher with an appropriate NSMutableURLRequest.
|
// 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:
|
// Caching:
|
||||||
//
|
//
|
||||||
@ -179,9 +181,8 @@
|
|||||||
// Note: cookies set while following redirects will be sent to the server, as
|
// Note: cookies set while following redirects will be sent to the server, as
|
||||||
// the redirects are followed by the fetcher.
|
// the redirects are followed by the fetcher.
|
||||||
//
|
//
|
||||||
// To completely disable cookies, similar to setting cookieStorageMethod to
|
// To completely disable cookies, adjust the session configuration appropriately
|
||||||
// kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration
|
// in the fetcher or fetcher service:
|
||||||
// appropriately in the fetcher or fetcher service:
|
|
||||||
// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
|
// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
|
||||||
// NSURLSessionConfiguration *config) {
|
// NSURLSessionConfiguration *config) {
|
||||||
// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
|
// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
|
||||||
@ -258,7 +259,6 @@
|
|||||||
// response(suggestedWillRetry);
|
// response(suggestedWillRetry);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
@ -271,93 +271,101 @@
|
|||||||
// By default it is stripped from non DEBUG builds. Developers can override
|
// By default it is stripped from non DEBUG builds. Developers can override
|
||||||
// this in their project settings.
|
// this in their project settings.
|
||||||
#ifndef STRIP_GTM_FETCH_LOGGING
|
#ifndef STRIP_GTM_FETCH_LOGGING
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
#define STRIP_GTM_FETCH_LOGGING 1
|
#define STRIP_GTM_FETCH_LOGGING 1
|
||||||
#else
|
#else
|
||||||
#define STRIP_GTM_FETCH_LOGGING 0
|
#define STRIP_GTM_FETCH_LOGGING 0
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Logs in debug builds.
|
// Logs in debug builds.
|
||||||
#ifndef GTMSESSION_LOG_DEBUG
|
#ifndef GTMSESSION_LOG_DEBUG
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
|
#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define GTMSESSION_LOG_DEBUG(...) do { } while (0)
|
#define GTMSESSION_LOG_DEBUG(...) \
|
||||||
#endif
|
do { \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG
|
// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG
|
||||||
// or NS_BLOCK_ASSERTIONS are defined.)
|
// or NS_BLOCK_ASSERTIONS are defined.)
|
||||||
#ifndef GTMSESSION_ASSERT_DEBUG
|
#ifndef GTMSESSION_ASSERT_DEBUG
|
||||||
#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
|
#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
|
||||||
#undef GTMSESSION_ASSERT_AS_LOG
|
#undef GTMSESSION_ASSERT_AS_LOG
|
||||||
#define GTMSESSION_ASSERT_AS_LOG 1
|
#define GTMSESSION_ASSERT_AS_LOG 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||||
#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
|
#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
|
||||||
#elif DEBUG
|
#elif DEBUG
|
||||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
|
#define GTMSESSION_ASSERT_DEBUG(pred, ...) \
|
||||||
#else
|
if (!(pred)) { \
|
||||||
#define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0)
|
NSLog(__VA_ARGS__); \
|
||||||
#endif
|
}
|
||||||
|
#else
|
||||||
|
#define GTMSESSION_ASSERT_DEBUG(pred, ...) \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Asserts in debug builds, logs in release builds (or logs in debug builds if
|
// Asserts in debug builds, logs in release builds (or logs in debug builds if
|
||||||
// GTMSESSION_ASSERT_AS_LOG is defined.)
|
// GTMSESSION_ASSERT_AS_LOG is defined.)
|
||||||
#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG
|
#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG
|
||||||
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
#if DEBUG && !GTMSESSION_ASSERT_AS_LOG
|
||||||
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__)
|
#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__)
|
|
||||||
#else
|
#else
|
||||||
#define GTM_LOG_SESSION_DELEGATE(...)
|
#define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) \
|
||||||
|
if (!(pred)) { \
|
||||||
|
NSLog(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#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
|
#ifndef GTM_NULLABLE
|
||||||
#if __has_feature(nullability) // Available starting in Xcode 6.3
|
#if __has_feature(nullability) // Available starting in Xcode 6.3
|
||||||
#define GTM_NULLABLE_TYPE __nullable
|
#define GTM_NULLABLE_TYPE __nullable
|
||||||
#define GTM_NONNULL_TYPE __nonnull
|
#define GTM_NONNULL_TYPE __nonnull
|
||||||
#define GTM_NULLABLE nullable
|
#define GTM_NULLABLE nullable
|
||||||
#define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
|
#define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
|
||||||
#define GTM_NULL_RESETTABLE null_resettable
|
#define GTM_NULL_RESETTABLE null_resettable
|
||||||
|
#define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
|
||||||
#define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
|
#define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
|
||||||
#define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
|
#else
|
||||||
#else
|
#define GTM_NULLABLE_TYPE
|
||||||
#define GTM_NULLABLE_TYPE
|
#define GTM_NONNULL_TYPE
|
||||||
#define GTM_NONNULL_TYPE
|
#define GTM_NULLABLE
|
||||||
#define GTM_NULLABLE
|
#define GTM_NONNULL_DECL
|
||||||
#define GTM_NONNULL_DECL
|
#define GTM_NULL_RESETTABLE
|
||||||
#define GTM_NULL_RESETTABLE
|
#define GTM_ASSUME_NONNULL_BEGIN
|
||||||
#define GTM_ASSUME_NONNULL_BEGIN
|
#define GTM_ASSUME_NONNULL_END
|
||||||
#define GTM_ASSUME_NONNULL_END
|
#endif // __has_feature(nullability)
|
||||||
#endif // __has_feature(nullability)
|
|
||||||
#endif // GTM_NULLABLE
|
#endif // GTM_NULLABLE
|
||||||
|
|
||||||
#ifndef GTM_DECLARE_GENERICS
|
#ifndef GTM_DECLARE_GENERICS
|
||||||
#if __has_feature(objc_generics)
|
#if __has_feature(objc_generics)
|
||||||
#define GTM_DECLARE_GENERICS 1
|
#define GTM_DECLARE_GENERICS 1
|
||||||
#else
|
#else
|
||||||
#define GTM_DECLARE_GENERICS 0
|
#define GTM_DECLARE_GENERICS 0
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GTM_NSArrayOf
|
#ifndef GTM_NSArrayOf
|
||||||
#if GTM_DECLARE_GENERICS
|
#if GTM_DECLARE_GENERICS
|
||||||
#define GTM_NSArrayOf(value) NSArray<value>
|
#define GTM_NSArrayOf(value) NSArray<value>
|
||||||
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
#define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
|
||||||
#else
|
#else
|
||||||
#define GTM_NSArrayOf(value) NSArray
|
#define GTM_NSArrayOf(value) NSArray
|
||||||
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
#define GTM_NSDictionaryOf(key, value) NSDictionary
|
||||||
#endif // __has_feature(objc_generics)
|
#endif // __has_feature(objc_generics)
|
||||||
#endif // GTM_NSArrayOf
|
#endif // GTM_NSArrayOf
|
||||||
|
|
||||||
// For iOS, the fetcher can declare itself a background task to allow fetches
|
// 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
|
// To disallow use of background tasks during fetches, the target should define
|
||||||
// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the
|
// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the
|
||||||
// skipBackgroundTask property to YES.
|
// skipBackgroundTask property to YES.
|
||||||
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING)
|
#if !defined(GTM_BACKGROUND_TASK_FETCHING) && \
|
||||||
#define GTM_BACKGROUND_TASK_FETCHING 1
|
(TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST)
|
||||||
|
#define GTM_BACKGROUND_TASK_FETCHING 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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)
|
#if !defined(GTMBridgeFetcher)
|
||||||
// These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h
|
// The bridge macros are deprecated, and should be replaced; GTMHTTPFetcher is no longer
|
||||||
#if GTM_USE_SESSION_FETCHER
|
// supported and all code should switch to use GTMSessionFetcher types directly.
|
||||||
// Macros to new fetcher class.
|
#define GTMBridgeFetcher GTMSessionFetcher
|
||||||
#define GTMBridgeFetcher GTMSessionFetcher
|
#define GTMBridgeFetcherService GTMSessionFetcherService
|
||||||
#define GTMBridgeFetcherService GTMSessionFetcherService
|
#define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
|
||||||
#define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
|
#define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
|
||||||
#define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
|
#define GTMBridgeCookieStorage GTMSessionCookieStorage
|
||||||
#define GTMBridgeCookieStorage GTMSessionCookieStorage
|
#define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
|
||||||
#define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
|
#define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
|
||||||
#define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
|
#define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
|
||||||
#define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
|
#define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
|
||||||
#define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
|
#define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest
|
||||||
#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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// When creating background sessions to perform out-of-process uploads and
|
// 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
|
// Apps targeting new SDKs can force the old behavior by defining
|
||||||
// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0.
|
// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0.
|
||||||
#ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
|
#ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
|
||||||
// Default to the on-launch behavior for iOS 13+.
|
// 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
|
#if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
||||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
|
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
|
||||||
#else
|
#else
|
||||||
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
|
#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GTM_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
//
|
//
|
||||||
@ -523,24 +509,26 @@ extern "C" {
|
|||||||
typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
|
typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
|
||||||
NSURLSessionConfiguration *configuration);
|
NSURLSessionConfiguration *configuration);
|
||||||
typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
|
typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
|
||||||
typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data,
|
typedef void (^GTMSessionFetcherCompletionHandler)(NSData *_Nullable data,
|
||||||
NSError * GTM_NULLABLE_TYPE error);
|
NSError *_Nullable error);
|
||||||
typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
|
typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
|
||||||
typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response);
|
typedef void (^GTMSessionFetcherBodyStreamProvider)(
|
||||||
typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition);
|
GTMSessionFetcherBodyStreamProviderResponse response);
|
||||||
typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response,
|
typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(
|
||||||
GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
|
NSURLSessionResponseDisposition disposition);
|
||||||
typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition,
|
typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(
|
||||||
NSURLCredential * GTM_NULLABLE_TYPE credential);
|
NSURLResponse *response, GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
|
||||||
typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher,
|
typedef void (^GTMSessionFetcherChallengeDispositionBlock)(
|
||||||
NSURLAuthenticationChallenge *challenge,
|
NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *_Nullable credential);
|
||||||
|
typedef void (^GTMSessionFetcherChallengeBlock)(
|
||||||
|
GTMSessionFetcher *fetcher, NSURLAuthenticationChallenge *challenge,
|
||||||
GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
|
GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
|
||||||
typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest);
|
typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest *_Nullable redirectedRequest);
|
||||||
typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse,
|
typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse,
|
||||||
NSURLRequest *redirectRequest,
|
NSURLRequest *redirectRequest,
|
||||||
GTMSessionFetcherWillRedirectResponse response);
|
GTMSessionFetcherWillRedirectResponse response);
|
||||||
typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer);
|
typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData *_Nullable buffer);
|
||||||
typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer,
|
typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData *_Nullable buffer,
|
||||||
int64_t bytesWritten,
|
int64_t bytesWritten,
|
||||||
int64_t totalBytesWritten,
|
int64_t totalBytesWritten,
|
||||||
int64_t totalBytesExpectedToWrite);
|
int64_t totalBytesExpectedToWrite);
|
||||||
@ -549,27 +537,26 @@ typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten,
|
|||||||
typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten,
|
typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten,
|
||||||
int64_t totalBytesWritten,
|
int64_t totalBytesWritten,
|
||||||
int64_t totalBytesExpectedToWrite);
|
int64_t totalBytesExpectedToWrite);
|
||||||
typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent,
|
typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, int64_t totalBytesSent,
|
||||||
int64_t totalBytesSent,
|
|
||||||
int64_t totalBytesExpectedToSend);
|
int64_t totalBytesExpectedToSend);
|
||||||
typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse);
|
typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(
|
||||||
typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse,
|
NSCachedURLResponse *_Nullable cachedResponse);
|
||||||
|
typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(
|
||||||
|
NSCachedURLResponse *proposedResponse,
|
||||||
GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
|
GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
|
||||||
typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry);
|
typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry);
|
||||||
typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry,
|
typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, NSError *_Nullable error,
|
||||||
NSError * GTM_NULLABLE_TYPE error,
|
|
||||||
GTMSessionFetcherRetryResponse response);
|
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 (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics);
|
||||||
|
|
||||||
typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response,
|
typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse *_Nullable response,
|
||||||
NSData * GTM_NULLABLE_TYPE data,
|
NSData *_Nullable data, NSError *_Nullable error);
|
||||||
NSError * GTM_NULLABLE_TYPE error);
|
|
||||||
typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest,
|
typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest,
|
||||||
GTMSessionFetcherTestResponse testResponse);
|
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
|
// Utility functions for applications self-identifying to servers via a
|
||||||
// user-agent header
|
// 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
|
// Applications may use this as a starting point for their own user agent strings, perhaps
|
||||||
// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to
|
// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to
|
||||||
// clean up any string being added to the user agent.
|
// 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
|
// Make a generic name and version for the current application, like
|
||||||
// com.example.MyApp/1.2.3 relying on the bundle identifier and the
|
// 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
|
// The bundle ID may be overridden as the base identifier string by
|
||||||
// adding to the bundle's Info.plist a "GTMUserAgentID" key.
|
// 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
|
// If no bundle ID or override is available, the process name preceded
|
||||||
// by "proc_" is used.
|
// 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"
|
// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1"
|
||||||
NSString *GTMFetcherSystemVersionString(void);
|
NSString *GTMFetcherSystemVersionString(void);
|
||||||
@ -615,16 +605,60 @@ NSString *GTMFetcherCleanedUserAgentString(NSString *str);
|
|||||||
// queue before calling this function.
|
// queue before calling this function.
|
||||||
//
|
//
|
||||||
// Failure is indicated by a returned data value of nil.
|
// 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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Completion handler passed to -[GTMFetcherDecoratorProtocol fetcherWillStart:completionHandler:].
|
||||||
|
typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLRequest *_Nullable,
|
||||||
|
NSError *_Nullable);
|
||||||
|
|
||||||
#if !GTM_USE_SESSION_FETCHER
|
// Allows intercepting a request and optionally modifying it before the request (or a retry)
|
||||||
@protocol GTMHTTPFetcherServiceProtocol;
|
// is sent. See `-[GTMSessionFetcherService addDecorator:]` and `-[GTMSessionFetcherService
|
||||||
#endif
|
// 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
|
// This protocol allows abstract references to the fetcher service, primarily for
|
||||||
// fetchers (which may be compiled without the fetcher service class present.)
|
// 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;
|
- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
|
||||||
|
|
||||||
@property(atomic, assign) BOOL reuseSession;
|
@property(atomic, assign) BOOL reuseSession;
|
||||||
- (GTM_NULLABLE NSURLSession *)session;
|
- (nullable NSURLSession *)session;
|
||||||
- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
|
- (nullable NSURLSession *)sessionForFetcherCreation;
|
||||||
- (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
|
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
|
||||||
- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
|
- (nullable NSDate *)stoppedAllFetchersDate;
|
||||||
|
|
||||||
// Methods for compatibility with the old GTMHTTPFetcher.
|
@property(atomic, readonly, strong, nullable) NSOperationQueue *delegateQueue;
|
||||||
@property(atomic, readonly, strong, GTM_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
|
@end // @protocol GTMSessionFetcherServiceProtocol
|
||||||
|
|
||||||
@ -661,7 +699,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
@required
|
@required
|
||||||
// This protocol allows us to call the authorizer without requiring its sources
|
// This protocol allows us to call the authorizer without requiring its sources
|
||||||
// in this project.
|
// in this project.
|
||||||
- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
|
- (void)authorizeRequest:(nullable NSMutableURLRequest *)request
|
||||||
delegate:(id)delegate
|
delegate:(id)delegate
|
||||||
didFinishSelector:(SEL)sel;
|
didFinishSelector:(SEL)sel;
|
||||||
|
|
||||||
@ -673,7 +711,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
|
|
||||||
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
|
||||||
|
|
||||||
@property(atomic, strong, readonly, GTM_NULLABLE) NSString *userEmail;
|
@property(atomic, strong, readonly, nullable) NSString *userEmail;
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
@ -685,14 +723,10 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// transmission of the bearer token unencrypted.
|
// transmission of the bearer token unencrypted.
|
||||||
@property(atomic, assign) BOOL shouldAuthorizeAllRequests;
|
@property(atomic, assign) BOOL shouldAuthorizeAllRequests;
|
||||||
|
|
||||||
- (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
|
- (void)authorizeRequest:(nullable NSMutableURLRequest *)request
|
||||||
completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler;
|
completionHandler:(void (^)(NSError *_Nullable error))handler;
|
||||||
|
|
||||||
#if GTM_USE_SESSION_FETCHER
|
@property(atomic, weak, nullable) id<GTMSessionFetcherServiceProtocol> fetcherService;
|
||||||
@property(atomic, weak, GTM_NULLABLE) id<GTMSessionFetcherServiceProtocol> fetcherService;
|
|
||||||
#else
|
|
||||||
@property(atomic, weak, GTM_NULLABLE) id<GTMHTTPFetcherServiceProtocol> fetcherService;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- (BOOL)primeForRefresh;
|
- (BOOL)primeForRefresh;
|
||||||
|
|
||||||
@ -704,7 +738,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:]
|
// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:]
|
||||||
@protocol GTMUIApplicationProtocol <NSObject>
|
@protocol GTMUIApplicationProtocol <NSObject>
|
||||||
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName
|
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName
|
||||||
expirationHandler:(void(^ __nullable)(void))handler;
|
expirationHandler:(void (^__nullable)(void))handler;
|
||||||
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
|
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
|
||||||
@end
|
@end
|
||||||
#endif
|
#endif
|
||||||
@ -722,7 +756,7 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// the connection is successfully created, the connection should retain the
|
// 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
|
// 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.
|
// 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
|
// Convenience methods that make a request, like +fetcherWithRequest
|
||||||
+ (instancetype)fetcherWithURL:(NSURL *)requestURL;
|
+ (instancetype)fetcherWithURL:(NSURL *)requestURL;
|
||||||
@ -730,11 +764,11 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
|
|
||||||
// Methods for creating fetchers to continue previous fetches.
|
// Methods for creating fetchers to continue previous fetches.
|
||||||
+ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData;
|
+ (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,
|
// Returns an array of currently active fetchers for background sessions,
|
||||||
// both restarted and newly created ones.
|
// both restarted and newly created ones.
|
||||||
+ (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions;
|
+ (NSArray<GTMSessionFetcher *> *)fetchersForBackgroundSessions;
|
||||||
|
|
||||||
// Designated initializer.
|
// 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 should typically be nil. Applications needing to customize
|
||||||
// the configuration may do so by setting the configurationBlock property.
|
// the configuration may do so by setting the configurationBlock property.
|
||||||
- (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request
|
- (instancetype)initWithRequest:(nullable NSURLRequest *)request
|
||||||
configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration;
|
configuration:(nullable NSURLSessionConfiguration *)configuration;
|
||||||
|
|
||||||
// The fetcher's request. This may not be set after beginFetch has been invoked. The request
|
// The fetcher's request. This may not be set after beginFetch has been invoked. The request
|
||||||
// may change due to redirects.
|
// 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
|
// Set a header field value on the request. Header field value changes will not
|
||||||
// affect a fetch after the fetch has begun.
|
// 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.
|
// 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
|
// 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.
|
// 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.
|
// the configuration should do so by setting the configurationBlock property.
|
||||||
// That allows the fetcher to pick an appropriate base configuration, with the
|
// That allows the fetcher to pick an appropriate base configuration, with the
|
||||||
// application setting only the configuration properties it needs to customize.
|
// 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.
|
// 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
|
// 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
|
// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior
|
||||||
// to invoking beginFetch.
|
// 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
|
// A session is created as needed by the fetcher. A fetcher service object
|
||||||
// may maintain sessions for multiple fetches to the same host.
|
// 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.
|
// The task in flight.
|
||||||
@property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask;
|
@property(atomic, readonly, nullable) NSURLSessionTask *sessionTask;
|
||||||
|
|
||||||
// The background session identifier.
|
// 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.
|
// Indicates a fetcher created to finish a background session task.
|
||||||
@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession;
|
@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
|
// 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
|
// length limits are unspecified, this should be kept small. Key names beginning with an underscore
|
||||||
// are reserved for use by the fetcher.
|
// 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.
|
// 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,
|
// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow,
|
||||||
// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh.
|
// 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.
|
// 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
|
// This method, intended for internal use returns the encoded information. The sessionUserInfo
|
||||||
// dictionary is stored as identifier metadata.
|
// 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
|
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
|
||||||
// The app should pass to this method the completion handler passed in the app delegate method
|
// 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
|
// 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.
|
// 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,
|
// By default, the fetcher prohibits localhost requests unless this property is set,
|
||||||
// or the GTM_ALLOW_INSECURE_REQUESTS build flag 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
|
// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually
|
||||||
// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage,
|
// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage,
|
||||||
// to hold cookies in memory.
|
// 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
|
// Setting the credential is optional; it is used if the connection receives
|
||||||
// an authentication challenge.
|
// 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
|
// Setting the proxy credential is optional; it is used if the connection
|
||||||
// receives an authentication challenge from a proxy.
|
// 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
|
// If body data, body file URL, or body stream provider is not set, then a GET request
|
||||||
// method is assumed.
|
// 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.
|
// 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.
|
// Length of body to send, expected or actual.
|
||||||
@property(atomic, readonly) int64_t bodyLength;
|
@property(atomic, readonly) int64_t bodyLength;
|
||||||
|
|
||||||
// The body stream provider may be called repeatedly to provide a body.
|
// The body stream provider may be called repeatedly to provide a body.
|
||||||
// Setting a body stream provider forces use of an upload task.
|
// 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.
|
// Object to add authorization to the request, if needed.
|
||||||
//
|
//
|
||||||
// This may not be changed once beginFetch has been invoked.
|
// 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.
|
// The service object that created and monitors this fetcher, if any.
|
||||||
@property(atomic, strong) id<GTMSessionFetcherServiceProtocol> service;
|
@property(atomic, strong) id<GTMSessionFetcherServiceProtocol> service;
|
||||||
|
|
||||||
// The host, if any, used to classify this fetcher in the fetcher 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.
|
// 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.
|
// the session task response.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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 delegate's optional challenge block may be used to inspect or alter
|
||||||
// the session task challenge.
|
// the session task challenge.
|
||||||
@ -954,18 +988,18 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// challenge.previousFailureCount to identify repeated invocations.
|
// challenge.previousFailureCount to identify repeated invocations.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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 delegate's optional willRedirect block may be used to inspect or alter
|
||||||
// the redirection.
|
// the redirection.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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.
|
// The optional send progress block reports body bytes uploaded.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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
|
// 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.
|
// 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.
|
// should empty its accumulation buffer.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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
|
// The optional received progress block may be used to monitor data
|
||||||
// received from a data task.
|
// received from a data task.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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
|
// The delegate's optional downloadProgress block may be used to monitor download
|
||||||
// progress in writing to disk.
|
// progress in writing to disk.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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
|
// 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.
|
// NSURLResponse. The user may prevent caching by passing nil to the block's response.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// 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
|
// Enable retrying; see comments at the top of this file. Setting
|
||||||
// retryEnabled=YES resets the min and max retry intervals.
|
// 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
|
// If present, this block should call the response block with YES to cause a retry or NO to end the
|
||||||
// fetch.
|
// fetch.
|
||||||
// See comments at the top of this file.
|
// 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.
|
// The optional block for collecting the metrics of the present session.
|
||||||
//
|
//
|
||||||
// This is called on the callback queue.
|
// This is called on the callback queue.
|
||||||
@property(atomic, copy, GTM_NULLABLE)
|
@property(atomic, copy, nullable)
|
||||||
GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
|
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
|
// Retry intervals must be strictly less than maxRetryInterval, else
|
||||||
// they will be limited to maxRetryInterval and no further retries will
|
// 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
|
// If the application has specified a destinationFileURL or an accumulateDataBlock
|
||||||
// for the fetcher, the data parameter passed to the callback will be nil.
|
// for the fetcher, the data parameter passed to the callback will be nil.
|
||||||
|
|
||||||
- (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate
|
- (void)beginFetchWithDelegate:(nullable id)delegate didFinishSelector:(nullable SEL)finishedSEL;
|
||||||
didFinishSelector:(GTM_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.
|
// Returns YES if this fetcher is in the process of fetching a URL.
|
||||||
@property(atomic, readonly, getter=isFetching) BOOL fetching;
|
@property(atomic, readonly, getter=isFetching) BOOL fetching;
|
||||||
@ -1074,57 +1108,61 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
- (void)stopFetching;
|
- (void)stopFetching;
|
||||||
|
|
||||||
// A block to be called when the fetch completes.
|
// 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.
|
// 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.
|
// Return the status code from the server response.
|
||||||
@property(atomic, readonly) NSInteger statusCode;
|
@property(atomic, readonly) NSInteger statusCode;
|
||||||
|
|
||||||
// Return the http headers from the response.
|
// 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.
|
// 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.
|
// Bytes downloaded so far.
|
||||||
@property(atomic, readonly) int64_t downloadedLength;
|
@property(atomic, readonly) int64_t downloadedLength;
|
||||||
|
|
||||||
// Buffer of currently-downloaded data, if available.
|
// 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.
|
// Local path to which the downloaded file will be moved.
|
||||||
//
|
//
|
||||||
// If a file already exists at the path, it will be overwritten.
|
// If a file already exists at the path, it will be overwritten.
|
||||||
// Will create the enclosing folders if they are not present.
|
// 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
|
// The time this fetcher originally began fetching. This is useful as a time
|
||||||
// barrier for ignoring irrelevant fetch notifications or callbacks.
|
// 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.
|
// 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.
|
// 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.
|
- (void)setProperty:(nullable id)obj
|
||||||
- (GTM_NULLABLE id)propertyForKey:(NSString *)key;
|
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.
|
// 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);
|
- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
||||||
|
|
||||||
// Log of request and response, if logging is enabled
|
// 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.
|
// 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;
|
//
|
||||||
|
// 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.
|
// 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
|
// 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
|
// property should be set in the fetcher service rather in the fetcher as it applies
|
||||||
// to a shared session.
|
// 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.
|
// 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.
|
// 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.
|
// sufficient reason for rejection from the app store.
|
||||||
//
|
//
|
||||||
// Returns NO if timed out.
|
// Returns NO if timed out.
|
||||||
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds
|
||||||
|
__deprecated_msg("Use XCTestExpectation instead");
|
||||||
|
|
||||||
// Test block is optional for testing.
|
// Test block is optional for testing.
|
||||||
//
|
//
|
||||||
@ -1162,9 +1203,9 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// should proceed.
|
// should proceed.
|
||||||
//
|
//
|
||||||
// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK.
|
// 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
|
// 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
|
// divide the response data into if the client has streaming enabled. The data will be divided up to
|
||||||
@ -1204,14 +1245,14 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// fetcher.deferResponseBodyLogging = NO;
|
// fetcher.deferResponseBodyLogging = NO;
|
||||||
// }];
|
// }];
|
||||||
|
|
||||||
@property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody;
|
@property(atomic, copy, nullable) NSString *logRequestBody;
|
||||||
@property(atomic, assign) BOOL deferResponseBodyLogging;
|
@property(atomic, assign) BOOL deferResponseBodyLogging;
|
||||||
@property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody;
|
@property(atomic, copy, nullable) NSString *logResponseBody;
|
||||||
|
|
||||||
// Internal logging support.
|
// Internal logging support.
|
||||||
@property(atomic, readonly) NSData *loggedStreamData;
|
@property(atomic, readonly) NSData *loggedStreamData;
|
||||||
@property(atomic, assign) BOOL hasLoggedError;
|
@property(atomic, assign) BOOL hasLoggedError;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL;
|
@property(atomic, strong, nullable) NSURL *redirectedFromURL;
|
||||||
- (void)appendLoggedStreamData:(NSData *)dataToAdd;
|
- (void)appendLoggedStreamData:(NSData *)dataToAdd;
|
||||||
- (void)clearLoggedStreamData;
|
- (void)clearLoggedStreamData;
|
||||||
|
|
||||||
@ -1220,9 +1261,10 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GTMSessionFetcher (BackwardsCompatibilityOnly)
|
@interface GTMSessionFetcher (BackwardsCompatibilityOnly)
|
||||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
|
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves;
|
||||||
// This method is just for compatibility with the old GTMHTTPFetcher class.
|
// this method is deprecated and will be removed soon.
|
||||||
- (void)setCookieStorageMethod:(NSInteger)method;
|
- (void)setCookieStorageMethod:(NSInteger)method
|
||||||
|
__deprecated_msg("Create an NSHTTPCookieStorage and set .cookieStorage directly.");
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Until we can just instantiate NSHTTPCookieStorage for local use, we'll
|
// 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.
|
// Add the array off cookies to the storage, replacing duplicates.
|
||||||
// Also removes expired cookies from the storage.
|
// Also removes expired cookies from the storage.
|
||||||
- (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies;
|
- (void)setCookies:(nullable NSArray<NSHTTPCookie *> *)cookies;
|
||||||
|
|
||||||
- (void)removeAllCookies;
|
- (void)removeAllCookies;
|
||||||
|
|
||||||
@ -1277,26 +1319,24 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
// Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not
|
// Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not
|
||||||
// defined or asserts are being logged instead.
|
// defined or asserts are being logged instead.
|
||||||
#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG)
|
#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG)
|
||||||
#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \
|
#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) varname##counter
|
||||||
varname ## counter
|
#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
|
||||||
#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
|
|
||||||
__GTMSessionMonitorSynchronizedVariableInner(varname, counter)
|
__GTMSessionMonitorSynchronizedVariableInner(varname, counter)
|
||||||
|
|
||||||
#define GTMSessionMonitorSynchronized(obj) \
|
#define GTMSessionMonitorSynchronized(obj) \
|
||||||
NS_VALID_UNTIL_END_OF_SCOPE id \
|
NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||||
__GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
|
||||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||||
allowRecursive:NO \
|
allowRecursive:NO \
|
||||||
functionName:__func__]
|
functionName:__func__]
|
||||||
|
|
||||||
#define GTMSessionMonitorRecursiveSynchronized(obj) \
|
#define GTMSessionMonitorRecursiveSynchronized(obj) \
|
||||||
NS_VALID_UNTIL_END_OF_SCOPE id \
|
NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
||||||
__GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
|
|
||||||
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
[[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
|
||||||
allowRecursive:YES \
|
allowRecursive:YES \
|
||||||
functionName:__func__]
|
functionName:__func__]
|
||||||
|
|
||||||
#define GTMSessionCheckSynchronized(obj) { \
|
#define GTMSessionCheckSynchronized(obj) \
|
||||||
|
{ \
|
||||||
GTMSESSION_ASSERT_DEBUG( \
|
GTMSESSION_ASSERT_DEBUG( \
|
||||||
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||||
@"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
|
@"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
|
||||||
@ -1304,12 +1344,13 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
__func__, [NSThread callStackSymbols]); \
|
__func__, [NSThread callStackSymbols]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GTMSessionCheckNotSynchronized(obj) { \
|
#define GTMSessionCheckNotSynchronized(obj) \
|
||||||
|
{ \
|
||||||
GTMSESSION_ASSERT_DEBUG( \
|
GTMSESSION_ASSERT_DEBUG( \
|
||||||
![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||||
@"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
|
@"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
|
||||||
@" on " #obj " in %s by %@. Call stack:\n%@", __func__, \
|
@" on " #obj " in %s by %@. Call stack:\n%@", \
|
||||||
[GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
__func__, [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
|
||||||
[NSThread callStackSymbols]); \
|
[NSThread callStackSymbols]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1323,16 +1364,23 @@ NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NS
|
|||||||
allowRecursive:(BOOL)allowRecursive
|
allowRecursive:(BOOL)allowRecursive
|
||||||
functionName:(const char *)functionName;
|
functionName:(const char *)functionName;
|
||||||
// Return the names of the functions that hold sync on the object, or nil if none.
|
// 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
|
@end
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define GTMSessionMonitorSynchronized(obj) do { } while (0)
|
#define GTMSessionMonitorSynchronized(obj) \
|
||||||
#define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0)
|
do { \
|
||||||
#define GTMSessionCheckSynchronized(obj) do { } while (0)
|
} while (0)
|
||||||
#define GTMSessionCheckNotSynchronized(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 // !DEBUG
|
||||||
#endif // __OBJC__
|
#endif // __OBJC__
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
GTM_ASSUME_NONNULL_END
|
|
||||||
|
|||||||
1031
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m
generated
1031
Pods/GTMSessionFetcher/Source/GTMSessionFetcher.m
generated
File diff suppressed because it is too large
Load Diff
@ -82,10 +82,9 @@
|
|||||||
+ (void)setLoggingDateStamp:(NSString *)dateStamp;
|
+ (void)setLoggingDateStamp:(NSString *)dateStamp;
|
||||||
+ (NSString *)loggingDateStamp;
|
+ (NSString *)loggingDateStamp;
|
||||||
|
|
||||||
// client apps can specify the directory for the log for this specific run,
|
// client apps can specify the directory for the log for this specific run:
|
||||||
// typically to match the directory used by another fetcher class, like:
|
|
||||||
//
|
//
|
||||||
// [GTMSessionFetcher setLogDirectoryForCurrentRun:[GTMHTTPFetcher logDirectoryForCurrentRun]];
|
// [GTMSessionFetcher setLogDirectoryForCurrentRun:logDirectoryPath];
|
||||||
//
|
//
|
||||||
// Setting this overrides the logging directory, process name, and date stamp when writing
|
// Setting this overrides the logging directory, process name, and date stamp when writing
|
||||||
// the log file.
|
// the log file.
|
||||||
|
|||||||
147
Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m
generated
147
Pods/GTMSessionFetcher/Source/GTMSessionFetcherLogging.m
generated
@ -23,7 +23,7 @@
|
|||||||
#import "GTMSessionFetcherLogging.h"
|
#import "GTMSessionFetcherLogging.h"
|
||||||
|
|
||||||
#ifndef STRIP_GTM_FETCH_LOGGING
|
#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
|
#endif
|
||||||
|
|
||||||
#if !STRIP_GTM_FETCH_LOGGING
|
#if !STRIP_GTM_FETCH_LOGGING
|
||||||
@ -45,15 +45,15 @@
|
|||||||
|
|
||||||
+ (instancetype)inputStreamWithStream:(NSInputStream *)input;
|
+ (instancetype)inputStreamWithStream:(NSInputStream *)input;
|
||||||
|
|
||||||
@property (assign) id readDelegate;
|
@property(assign) id readDelegate;
|
||||||
@property (assign) SEL readSelector;
|
@property(assign) SEL readSelector;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
#else
|
#else
|
||||||
@class GTMReadMonitorInputStream;
|
@class GTMReadMonitorInputStream;
|
||||||
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||||
|
|
||||||
@interface GTMSessionFetcher (GTMHTTPFetcherLoggingUtilities)
|
@interface GTMSessionFetcher (GTMSessionFetcherLoggingUtilities)
|
||||||
|
|
||||||
+ (NSString *)headersStringForDictionary:(NSDictionary *)dict;
|
+ (NSString *)headersStringForDictionary:(NSDictionary *)dict;
|
||||||
+ (NSString *)snipSubstringOfString:(NSString *)originalStr
|
+ (NSString *)snipSubstringOfString:(NSString *)originalStr
|
||||||
@ -157,7 +157,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
if (![fileMgr createDirectoryAtPath:logDirectory
|
if (![fileMgr createDirectoryAtPath:logDirectory
|
||||||
withIntermediateDirectories:YES
|
withIntermediateDirectories:YES
|
||||||
attributes:nil
|
attributes:nil
|
||||||
error:NULL]) return nil;
|
error:NULL])
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
gLogDirectoryForCurrentRun = logDirectory;
|
gLogDirectoryForCurrentRun = logDirectory;
|
||||||
|
|
||||||
@ -243,18 +244,15 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
if ([itemURL isEqual:logDirectoryForCurrentRun]) continue;
|
if ([itemURL isEqual:logDirectoryForCurrentRun]) continue;
|
||||||
|
|
||||||
NSDate *modDate;
|
NSDate *modDate;
|
||||||
if ([itemURL getResourceValue:&modDate
|
if ([itemURL getResourceValue:&modDate forKey:NSURLContentModificationDateKey error:&error]) {
|
||||||
forKey:NSURLContentModificationDateKey
|
|
||||||
error:&error]) {
|
|
||||||
if ([modDate compare:cutoffDate] == NSOrderedAscending) {
|
if ([modDate compare:cutoffDate] == NSOrderedAscending) {
|
||||||
if (![fileMgr removeItemAtURL:itemURL error:&error]) {
|
if (![fileMgr removeItemAtURL:itemURL error:&error]) {
|
||||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@",
|
NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", itemURL.path, error);
|
||||||
itemURL.path, error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@",
|
NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", itemURL.path,
|
||||||
itemURL.path, error);
|
error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +267,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
// if the content type is JSON and we have the parsing class available, use that
|
// if the content type is JSON and we have the parsing class available, use that
|
||||||
if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) {
|
if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) {
|
||||||
// convert from JSON string to NSObjects and back to a formatted string
|
// convert from JSON string to NSObjects and back to a formatted string
|
||||||
NSMutableDictionary *obj = [NSJSONSerialization JSONObjectWithData:inputData
|
NSMutableDictionary *obj =
|
||||||
|
[NSJSONSerialization JSONObjectWithData:inputData
|
||||||
options:NSJSONReadingMutableContainers
|
options:NSJSONReadingMutableContainers
|
||||||
error:NULL];
|
error:NULL];
|
||||||
if (obj) {
|
if (obj) {
|
||||||
@ -287,8 +286,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
options:NSJSONWritingPrettyPrinted
|
options:NSJSONWritingPrettyPrinted
|
||||||
error:NULL];
|
error:NULL];
|
||||||
if (data) {
|
if (data) {
|
||||||
NSString *jsonStr = [[NSString alloc] initWithData:data
|
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||||
encoding:NSUTF8StringEncoding];
|
|
||||||
return jsonStr;
|
return jsonStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,10 +303,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath];
|
gIsXMLLintAvailable = [[NSFileManager defaultManager] fileExistsAtPath:kXMLLintPath];
|
||||||
gHasCheckedAvailability = YES;
|
gHasCheckedAvailability = YES;
|
||||||
}
|
}
|
||||||
if (gIsXMLLintAvailable
|
if (gIsXMLLintAvailable && inputData.length > 5 && strncmp(inputData.bytes, "<?xml", 5) == 0) {
|
||||||
&& inputData.length > 5
|
|
||||||
&& strncmp(inputData.bytes, "<?xml", 5) == 0) {
|
|
||||||
|
|
||||||
// call xmllint to format the data
|
// call xmllint to format the data
|
||||||
NSTask *task = [[NSTask alloc] init];
|
NSTask *task = [[NSTask alloc] init];
|
||||||
[task setLaunchPath:kXMLLintPath];
|
[task setLaunchPath:kXMLLintPath];
|
||||||
@ -342,8 +337,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
// we can't call external tasks on the iPhone; leave the XML unformatted
|
// we can't call external tasks on the iPhone; leave the XML unformatted
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSString *dataStr = [[NSString alloc] initWithData:inputData
|
NSString *dataStr = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
|
||||||
encoding:NSUTF8StringEncoding];
|
|
||||||
return dataStr;
|
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
|
// For parts that fail, a replacement string showing the part header and <<n bytes>> is supplied
|
||||||
// in place of the binary data.
|
// in place of the binary data.
|
||||||
|
|
||||||
- (NSString *)stringFromStreamData:(NSData *)data
|
- (NSString *)stringFromStreamData:(NSData *)data contentType:(NSString *)contentType {
|
||||||
contentType:(NSString *)contentType {
|
|
||||||
|
|
||||||
if (!data) return nil;
|
if (!data) return nil;
|
||||||
|
|
||||||
// optimistically, see if the whole data block is UTF-8
|
// optimistically, see if the whole data block is UTF-8
|
||||||
NSString *streamDataStr = [self formattedStringFromData:data
|
NSString *streamDataStr = [self formattedStringFromData:data contentType:contentType JSON:NULL];
|
||||||
contentType:contentType
|
|
||||||
JSON:NULL];
|
|
||||||
if (streamDataStr) return streamDataStr;
|
if (streamDataStr) return streamDataStr;
|
||||||
|
|
||||||
// Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an
|
// 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
|
NSString *mungedStr = [[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding];
|
||||||
encoding:NSUTF8StringEncoding];
|
|
||||||
if (mungedStr) {
|
if (mungedStr) {
|
||||||
|
|
||||||
// scan for the boundary string
|
// scan for the boundary string
|
||||||
NSString *boundary = nil;
|
NSString *boundary = nil;
|
||||||
NSScanner *scanner = [NSScanner scannerWithString:mungedStr];
|
NSScanner *scanner = [NSScanner scannerWithString:mungedStr];
|
||||||
|
|
||||||
if ([scanner scanUpToString:@"\r\n" intoString:&boundary]
|
if ([scanner scanUpToString:@"\r\n" intoString:&boundary] && [boundary hasPrefix:@"--"]) {
|
||||||
&& [boundary hasPrefix:@"--"]) {
|
|
||||||
|
|
||||||
// we found a boundary string; use it to divide the string into parts
|
// we found a boundary string; use it to divide the string into parts
|
||||||
NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary];
|
NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary];
|
||||||
|
|
||||||
@ -412,8 +398,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
header = @"";
|
header = @"";
|
||||||
}
|
}
|
||||||
// make a part string with the header and <<n bytes>>
|
// make a part string with the header and <<n bytes>>
|
||||||
NSString *binStr = [NSString stringWithFormat:@"\r%@\r<<%lu bytes>>\r",
|
NSString *binStr = [NSString
|
||||||
header, (long)(partSize - header.length)];
|
stringWithFormat:@"\r%@\r<<%lu bytes>>\r", header, (long)(partSize - header.length)];
|
||||||
[origParts addObject:binStr];
|
[origParts addObject:binStr];
|
||||||
}
|
}
|
||||||
offset += partSize + boundary.length;
|
offset += partSize + boundary.length;
|
||||||
@ -465,10 +451,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
int64_t responseDataLength = self.downloadedLength;
|
int64_t responseDataLength = self.downloadedLength;
|
||||||
if (responseDataLength > 0) {
|
if (responseDataLength > 0) {
|
||||||
NSData *downloadedData = self.downloadedData;
|
NSData *downloadedData = self.downloadedData;
|
||||||
if (downloadedData == nil
|
if (downloadedData == nil && responseDataLength > 0 && responseDataLength < 20000 &&
|
||||||
&& responseDataLength > 0
|
self.destinationFileURL) {
|
||||||
&& responseDataLength < 20000
|
|
||||||
&& self.destinationFileURL) {
|
|
||||||
// There's a download file that's not too big, so get the data to display from the downloaded
|
// There's a download file that's not too big, so get the data to display from the downloaded
|
||||||
// file.
|
// file.
|
||||||
NSURL *destinationURL = self.destinationFileURL;
|
NSURL *destinationURL = self.destinationFileURL;
|
||||||
@ -482,8 +466,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
NSData *dataToWrite = nil;
|
NSData *dataToWrite = nil;
|
||||||
if (responseDataStr) {
|
if (responseDataStr) {
|
||||||
// we were able to make a UTF-8 string from the response data
|
// we were able to make a UTF-8 string from the response data
|
||||||
if ([responseMIMEType isEqual:@"application/atom+xml"]
|
if ([responseMIMEType isEqual:@"application/atom+xml"] ||
|
||||||
|| [responseMIMEType hasSuffix:@"/xml"]) {
|
[responseMIMEType hasSuffix:@"/xml"]) {
|
||||||
responseDataExtn = @"xml";
|
responseDataExtn = @"xml";
|
||||||
dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding];
|
dataToWrite = [responseDataStr dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
}
|
}
|
||||||
@ -505,32 +489,36 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
// if we have an extension, save the raw data in a file with that extension
|
// if we have an extension, save the raw data in a file with that extension
|
||||||
if (responseDataExtn && dataToWrite) {
|
if (responseDataExtn && dataToWrite) {
|
||||||
// generate a response file base name like
|
// 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];
|
responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn];
|
||||||
NSString *responseDataFilePath = [logDirectory stringByAppendingPathComponent:responseDataFileName];
|
NSString *responseDataFilePath =
|
||||||
|
[logDirectory stringByAppendingPathComponent:responseDataFileName];
|
||||||
|
|
||||||
NSError *downloadedError = nil;
|
NSError *downloadedError = nil;
|
||||||
if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath
|
if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath
|
||||||
options:0
|
options:0
|
||||||
error:&downloadedError]) {
|
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
|
// we'll have one main html file per run of the app
|
||||||
NSString *htmlName = [[self class] htmlFileName];
|
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
|
// if the html file exists (from logging previous fetches) we don't need
|
||||||
// to re-write the header or the scripts
|
// to re-write the header or the scripts
|
||||||
NSFileManager *fileMgr = [NSFileManager defaultManager];
|
NSFileManager *fileMgr = [NSFileManager defaultManager];
|
||||||
BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath];
|
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
|
// we need a header to say we'll have UTF-8 text
|
||||||
if (!didFileExist) {
|
if (!didFileExist) {
|
||||||
[outputHTML appendFormat:@"<html><head><meta http-equiv=\"content-type\" "
|
[outputHTML
|
||||||
|
appendFormat:@"<html><head><meta http-equiv=\"content-type\" "
|
||||||
"content=\"text/html; charset=UTF-8\"><title>%@ HTTP fetch log %@</title>",
|
"content=\"text/html; charset=UTF-8\"><title>%@ HTTP fetch log %@</title>",
|
||||||
processName, [[self class] loggingDateStamp]];
|
processName, [[self class] loggingDateStamp]];
|
||||||
}
|
}
|
||||||
@ -545,7 +533,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
if (comment.length > 0) {
|
if (comment.length > 0) {
|
||||||
[outputHTML appendFormat:@"%@ ", comment];
|
[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;
|
NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow;
|
||||||
[outputHTML appendFormat:@"elapsed: %5.3fsec<br>", elapsed];
|
[outputHTML appendFormat:@"elapsed: %5.3fsec<br>", elapsed];
|
||||||
|
|
||||||
@ -590,10 +579,11 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
}
|
}
|
||||||
matchHdr = [requestHeaders objectForKey:@"If-None-Match"];
|
matchHdr = [requestHeaders objectForKey:@"If-None-Match"];
|
||||||
if (matchHdr) {
|
if (matchHdr) {
|
||||||
headerDetails = [headerDetails stringByAppendingString:@" <i>if-none-match</i>"];
|
headerDetails =
|
||||||
|
[headerDetails stringByAppendingString:@" <i>if-none-match</i>"];
|
||||||
}
|
}
|
||||||
[outputHTML appendFormat:@" headers: %d %@<br>",
|
[outputHTML appendFormat:@" headers: %d %@<br>", (int)numberOfRequestHeaders,
|
||||||
(int)numberOfRequestHeaders, headerDetails];
|
headerDetails];
|
||||||
} else {
|
} else {
|
||||||
[outputHTML appendFormat:@" headers: none<br>"];
|
[outputHTML appendFormat:@" headers: none<br>"];
|
||||||
}
|
}
|
||||||
@ -639,8 +629,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
bodyDataStr = [logRequestBody copy];
|
bodyDataStr = [logRequestBody copy];
|
||||||
self.logRequestBody = nil;
|
self.logRequestBody = nil;
|
||||||
} else {
|
} else {
|
||||||
bodyDataStr = [self stringFromStreamData:bodyData
|
bodyDataStr = [self stringFromStreamData:bodyData contentType:postType];
|
||||||
contentType:postType];
|
|
||||||
if (bodyDataStr) {
|
if (bodyDataStr) {
|
||||||
// remove OAuth 2 client secret and refresh token
|
// remove OAuth 2 client secret and refresh token
|
||||||
bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr
|
bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr
|
||||||
@ -674,10 +663,10 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
NSString *jsonMessage = [jsonError valueForKey:@"message"];
|
NSString *jsonMessage = [jsonError valueForKey:@"message"];
|
||||||
if (jsonCode || jsonMessage) {
|
if (jsonCode || jsonMessage) {
|
||||||
// 2691 = ⚑
|
// 2691 = ⚑
|
||||||
NSString *const jsonErrFmt =
|
NSString *const jsonErrFmt = @" <i>JSON error:</i> <FONT "
|
||||||
@" <i>JSON error:</i> <FONT COLOR='#FF00FF'>%@ %@ ⚑</FONT>";
|
@"COLOR='#FF00FF'>%@ %@ ⚑</FONT>";
|
||||||
statusString = [statusString stringByAppendingFormat:jsonErrFmt,
|
statusString =
|
||||||
jsonCode ? jsonCode : @"",
|
[statusString stringByAppendingFormat:jsonErrFmt, jsonCode ? jsonCode : @"",
|
||||||
jsonMessage ? jsonMessage : @""];
|
jsonMessage ? jsonMessage : @""];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,8 +688,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
@"<FONT COLOR='#FF00FF'>response URL:</FONT> <code>%@</code><br>\n";
|
@"<FONT COLOR='#FF00FF'>response URL:</FONT> <code>%@</code><br>\n";
|
||||||
responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]];
|
responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]];
|
||||||
}
|
}
|
||||||
[outputHTML appendFormat:@"<b>response:</b> status %@<br>\n%@",
|
[outputHTML appendFormat:@"<b>response:</b> status %@<br>\n%@", statusString,
|
||||||
statusString, responseURLStr];
|
responseURLStr];
|
||||||
// Write the response headers
|
// Write the response headers
|
||||||
NSUInteger numberOfResponseHeaders = responseHeaders.count;
|
NSUInteger numberOfResponseHeaders = responseHeaders.count;
|
||||||
if (numberOfResponseHeaders > 0) {
|
if (numberOfResponseHeaders > 0) {
|
||||||
@ -729,20 +718,21 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
// Make a small inline image that links to the full image file
|
// Make a small inline image that links to the full image file
|
||||||
[outputHTML appendFormat:@" data: %lld bytes, <code>%@</code><br>",
|
[outputHTML appendFormat:@" data: %lld bytes, <code>%@</code><br>",
|
||||||
responseDataLength, responseMIMEType];
|
responseDataLength, responseMIMEType];
|
||||||
NSString *const fmt =
|
NSString *const fmt = @"<a href=\"%@\"><img src='%@' alt='image' style='border:solid "
|
||||||
@"<a href=\"%@\"><img src='%@' alt='image' style='border:solid thin;max-height:32'></a>\n";
|
@"thin;max-height:32'></a>\n";
|
||||||
[outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName];
|
[outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName];
|
||||||
} else {
|
} else {
|
||||||
// The response data was XML; link to the xml file
|
// The response data was XML; link to the xml file
|
||||||
NSString *const fmt =
|
NSString *const fmt = @" data: %lld bytes, "
|
||||||
@" data: %lld bytes, <code>%@</code> <i><a href=\"%@\">%@</a></i>\n";
|
@"<code>%@</code> <i><a href=\"%@\">%@</a></i>\n";
|
||||||
[outputHTML appendFormat:fmt, responseDataLength, responseMIMEType,
|
[outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, responseDataFileName,
|
||||||
responseDataFileName, [responseDataFileName pathExtension]];
|
[responseDataFileName pathExtension]];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The response data was not an image; just show the length and MIME type
|
// The response data was not an image; just show the length and MIME type
|
||||||
[outputHTML appendFormat:@" data: %lld bytes, <code>%@</code>\n",
|
[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
|
// Make a single string of the request and response, suitable for copying
|
||||||
// to the clipboard and pasting into a bug report
|
// to the clipboard and pasting into a bug report
|
||||||
@ -767,7 +757,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
[copyable appendString:@"\n"];
|
[copyable appendString:@"\n"];
|
||||||
}
|
}
|
||||||
if (response) {
|
if (response) {
|
||||||
[copyable appendFormat:@"Response: status %d\n", (int) status];
|
[copyable appendFormat:@"Response: status %d\n", (int)status];
|
||||||
[copyable appendFormat:@"Response headers:\n%@\n",
|
[copyable appendFormat:@"Response headers:\n%@\n",
|
||||||
[[self class] headersStringForDictionary:responseHeaders]];
|
[[self class] headersStringForDictionary:responseHeaders]];
|
||||||
[copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength];
|
[copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength];
|
||||||
@ -783,8 +773,8 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
} else {
|
} else {
|
||||||
// Even though it's redundant, we'll put in text to indicate that all the bytes are binary.
|
// Even though it's redundant, we'll put in text to indicate that all the bytes are binary.
|
||||||
if (self.destinationFileURL) {
|
if (self.destinationFileURL) {
|
||||||
[copyable appendFormat:@"<<%lld bytes>> to file %@\n",
|
[copyable appendFormat:@"<<%lld bytes>> to file %@\n", responseDataLength,
|
||||||
responseDataLength, self.destinationFileURL.path];
|
self.destinationFileURL.path];
|
||||||
} else {
|
} else {
|
||||||
[copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength];
|
[copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength];
|
||||||
}
|
}
|
||||||
@ -819,11 +809,10 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
[outputHTML appendString:@"<br><hr><p>"];
|
[outputHTML appendString:@"<br><hr><p>"];
|
||||||
|
|
||||||
// Append the HTML to the main output file
|
// Append the HTML to the main output file
|
||||||
const char* htmlBytes = outputHTML.UTF8String;
|
const char *htmlBytes = outputHTML.UTF8String;
|
||||||
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath
|
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath append:YES];
|
||||||
append:YES];
|
|
||||||
[stream open];
|
[stream open];
|
||||||
[stream write:(const uint8_t *) htmlBytes maxLength:strlen(htmlBytes)];
|
[stream write:(const uint8_t *)htmlBytes maxLength:strlen(htmlBytes)];
|
||||||
[stream close];
|
[stream close];
|
||||||
|
|
||||||
// Make a symlink to the latest html
|
// Make a symlink to the latest html
|
||||||
@ -832,9 +821,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName];
|
NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName];
|
||||||
|
|
||||||
[fileMgr removeItemAtPath:symlinkPath error:NULL];
|
[fileMgr removeItemAtPath:symlinkPath error:NULL];
|
||||||
[fileMgr createSymbolicLinkAtPath:symlinkPath
|
[fileMgr createSymbolicLinkAtPath:symlinkPath withDestinationPath:htmlPath error:NULL];
|
||||||
withDestinationPath:htmlPath
|
|
||||||
error:NULL];
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
static BOOL gReportedLoggingPath = NO;
|
static BOOL gReportedLoggingPath = NO;
|
||||||
if (!gReportedLoggingPath) {
|
if (!gReportedLoggingPath) {
|
||||||
@ -898,9 +885,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
readIntoBuffer:(void *)buffer
|
readIntoBuffer:(void *)buffer
|
||||||
length:(int64_t)length {
|
length:(int64_t)length {
|
||||||
// append the captured data
|
// append the captured data
|
||||||
NSData *data = [NSData dataWithBytesNoCopy:buffer
|
NSData *data = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)length freeWhenDone:NO];
|
||||||
length:(NSUInteger)length
|
|
||||||
freeWhenDone:NO];
|
|
||||||
[self appendLoggedStreamData:data];
|
[self appendLoggedStreamData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,9 +908,7 @@ static NSString *gLoggingProcessName = nil;
|
|||||||
NSUInteger originalLength = originalStr.length;
|
NSUInteger originalLength = originalStr.length;
|
||||||
NSUInteger startOfTarget = NSMaxRange(startRange);
|
NSUInteger startOfTarget = NSMaxRange(startRange);
|
||||||
NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget);
|
NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget);
|
||||||
NSRange endRange = [originalStr rangeOfString:endStr
|
NSRange endRange = [originalStr rangeOfString:endStr options:0 range:targetAndRest];
|
||||||
options:0
|
|
||||||
range:targetAndRest];
|
|
||||||
NSRange replaceRange;
|
NSRange replaceRange;
|
||||||
if (endRange.location == NSNotFound) {
|
if (endRange.location == NSNotFound) {
|
||||||
// Found no end marker so replace to end of string
|
// Found no end marker so replace to end of string
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#import "GTMSessionFetcher.h"
|
#import "GTMSessionFetcher.h"
|
||||||
|
|
||||||
GTM_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
// Notifications.
|
// Notifications.
|
||||||
|
|
||||||
@ -34,12 +34,14 @@ GTM_ASSUME_NONNULL_BEGIN
|
|||||||
extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification;
|
extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification;
|
||||||
extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
||||||
|
|
||||||
@interface GTMSessionFetcherService : NSObject<GTMSessionFetcherServiceProtocol>
|
@interface GTMSessionFetcherService : NSObject <GTMSessionFetcherServiceProtocol>
|
||||||
|
|
||||||
// Queues of delayed and running fetchers. Each dictionary contains arrays
|
// Queues of delayed and running fetchers. Each dictionary contains arrays
|
||||||
// of GTMSessionFetcher *fetchers, keyed by NSString *host
|
// of GTMSessionFetcher *fetchers, keyed by NSString *host
|
||||||
@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *delayedFetchersByHost;
|
@property(atomic, strong, readonly, nullable)
|
||||||
@property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSArray *) *runningFetchersByHost;
|
NSDictionary<NSString *, NSArray *> *delayedFetchersByHost;
|
||||||
|
@property(atomic, strong, readonly, nullable)
|
||||||
|
NSDictionary<NSString *, NSArray *> *runningFetchersByHost;
|
||||||
|
|
||||||
// A max value of 0 means no fetchers should be delayed.
|
// A max value of 0 means no fetchers should be delayed.
|
||||||
// The default limit is 10 simultaneous fetchers targeting each host.
|
// The default limit is 10 simultaneous fetchers targeting each host.
|
||||||
@ -48,24 +50,24 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
|||||||
@property(atomic, assign) NSUInteger maxRunningFetchersPerHost;
|
@property(atomic, assign) NSUInteger maxRunningFetchersPerHost;
|
||||||
|
|
||||||
// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions
|
// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration;
|
@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration;
|
||||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock;
|
@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage;
|
@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage;
|
||||||
@property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue;
|
@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue;
|
||||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock;
|
@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential;
|
@property(atomic, strong, nullable) NSURLCredential *credential;
|
||||||
@property(atomic, strong) NSURLCredential *proxyCredential;
|
@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 allowLocalhostRequest;
|
||||||
@property(atomic, assign) BOOL allowInvalidServerCertificates;
|
@property(atomic, assign) BOOL allowInvalidServerCertificates;
|
||||||
@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
|
@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 maxRetryInterval;
|
||||||
@property(atomic, assign) NSTimeInterval minRetryInterval;
|
@property(atomic, assign) NSTimeInterval minRetryInterval;
|
||||||
@property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties;
|
@property(atomic, copy, nullable) NSDictionary<NSString *, id> *properties;
|
||||||
@property(atomic, copy, GTM_NULLABLE)
|
@property(atomic, copy, nullable)
|
||||||
GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
|
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
|
#if GTM_BACKGROUND_TASK_FETCHING
|
||||||
@property(atomic, assign) BOOL skipBackgroundTask;
|
@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.
|
// 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.
|
// 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
|
// 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
|
// not authorize its requests, the fetcher's authorizer property may be set to nil
|
||||||
// before the fetch begins.
|
// 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
|
// 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
|
// 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.
|
// 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.
|
// When enabled, indicates the same session should be used by subsequent fetchers.
|
||||||
//
|
//
|
||||||
@ -120,8 +122,7 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
|||||||
// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of
|
// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of
|
||||||
// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to
|
// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to
|
||||||
// be overridden.
|
// be overridden.
|
||||||
- (id)fetcherWithRequest:(NSURLRequest *)request
|
- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass;
|
||||||
fetcherClass:(Class)fetcherClass;
|
|
||||||
|
|
||||||
- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
|
- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
|
||||||
|
|
||||||
@ -133,24 +134,33 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
|||||||
// by the service which have been started and have not yet stopped.
|
// by the service which have been started and have not yet stopped.
|
||||||
//
|
//
|
||||||
// Returns an array of fetcher objects, or nil if none.
|
// 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.
|
// Search for running or delayed fetchers with the specified URL.
|
||||||
//
|
//
|
||||||
// Returns an array of fetcher objects found, or nil if none found.
|
// 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;
|
- (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.
|
// Methods for use by the fetcher class only.
|
||||||
- (GTM_NULLABLE NSURLSession *)session;
|
- (nullable NSURLSession *)session;
|
||||||
- (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
|
- (nullable NSURLSession *)sessionForFetcherCreation;
|
||||||
- (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
|
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
|
||||||
- (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
|
- (nullable NSDate *)stoppedAllFetchersDate;
|
||||||
|
|
||||||
// The testBlock can inspect its fetcher parameter's request property to
|
// The testBlock can inspect its fetcher parameter's request property to
|
||||||
// determine which fetcher is being faked.
|
// determine which fetcher is being faked.
|
||||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock;
|
@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -166,12 +176,14 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
|||||||
// or fetcher; the test block can inspect the fetcher's request or other properties.
|
// or fetcher; the test block can inspect the fetcher's request or other properties.
|
||||||
//
|
//
|
||||||
// See the description of the testBlock property below.
|
// See the description of the testBlock property below.
|
||||||
+ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil
|
+ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil
|
||||||
fakedError:(GTM_NULLABLE NSError *)fakedErrorOrNil;
|
fakedError:(nullable NSError *)fakedErrorOrNil;
|
||||||
+ (instancetype)mockFetcherServiceWithFakedData:(GTM_NULLABLE NSData *)fakedDataOrNil
|
+ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil
|
||||||
fakedResponse:(NSHTTPURLResponse *)fakedResponse
|
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)
|
// 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.
|
// until all running and delayed fetchers have completed.
|
||||||
//
|
//
|
||||||
@ -181,16 +193,18 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;
|
|||||||
// sufficient reason for rejection from the app store.
|
// sufficient reason for rejection from the app store.
|
||||||
//
|
//
|
||||||
// Returns NO if timed out.
|
// Returns NO if timed out.
|
||||||
- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds;
|
- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds
|
||||||
|
__deprecated_msg("Use XCTestExpectation instead");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GTMSessionFetcherService (BackwardsCompatibilityOnly)
|
@interface GTMSessionFetcherService (BackwardsCompatibilityOnly)
|
||||||
|
|
||||||
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
|
// Clients using GTMSessionFetcher should set the cookie storage explicitly themselves;
|
||||||
// This method is just for compatibility with the old fetcher.
|
// this property is deprecated and will be removed soon.
|
||||||
@property(atomic, assign) NSInteger cookieStorageMethod;
|
@property(atomic, assign) NSInteger cookieStorageMethod __deprecated_msg(
|
||||||
|
"Create an NSHTTPCookieStorage and set .cookieStorage directly.");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
GTM_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
240
Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m
generated
240
Pods/GTMSessionFetcher/Source/GTMSessionFetcherService.m
generated
@ -19,15 +19,15 @@
|
|||||||
|
|
||||||
#import "GTMSessionFetcherService.h"
|
#import "GTMSessionFetcherService.h"
|
||||||
|
|
||||||
NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification
|
NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification =
|
||||||
= @"kGTMSessionFetcherServiceSessionBecameInvalidNotification";
|
@"kGTMSessionFetcherServiceSessionBecameInvalidNotification";
|
||||||
NSString *const kGTMSessionFetcherServiceSessionKey
|
NSString *const kGTMSessionFetcherServiceSessionKey = @"kGTMSessionFetcherServiceSessionKey";
|
||||||
= @"kGTMSessionFetcherServiceSessionKey";
|
|
||||||
|
|
||||||
#if !GTMSESSION_BUILD_COMBINED_SOURCES
|
#if !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||||
@interface GTMSessionFetcher (ServiceMethods)
|
@interface GTMSessionFetcher (ServiceMethods)
|
||||||
- (BOOL)beginFetchMayDelay:(BOOL)mayDelay
|
- (BOOL)beginFetchMayDelay:(BOOL)mayDelay
|
||||||
mayAuthorize:(BOOL)mayAuthorize;
|
mayAuthorize:(BOOL)mayAuthorize
|
||||||
|
mayDecorate:(BOOL)mayDecorate;
|
||||||
@end
|
@end
|
||||||
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
#endif // !GTMSESSION_BUILD_COMBINED_SOURCES
|
||||||
|
|
||||||
@ -36,6 +36,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost;
|
@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost;
|
||||||
@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost;
|
@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost;
|
||||||
|
|
||||||
|
// Ordered collection of id<GTMFetcherDecoratorProtocol>, held weakly.
|
||||||
|
@property(atomic, strong, readonly) NSPointerArray *decoratorsPointerArray;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Since NSURLSession doesn't support a separate delegate per task (!), instances of this
|
// 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
|
// This class maps a session's tasks to fetchers, and resends delegate messages to the task's
|
||||||
// fetcher.
|
// fetcher.
|
||||||
@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject<NSURLSessionDelegate>
|
@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject <NSURLSessionDelegate>
|
||||||
|
|
||||||
// The session for the tasks in this dispatcher's task-to-fetcher map.
|
// The session for the tasks in this dispatcher's task-to-fetcher map.
|
||||||
@property(atomic) NSURLSession *session;
|
@property(atomic) NSURLSession *session;
|
||||||
@ -54,12 +57,10 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
// The current discard timer.
|
// The current discard timer.
|
||||||
@property(atomic, readonly) NSTimer *discardTimer;
|
@property(atomic, readonly) NSTimer *discardTimer;
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService
|
- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService
|
||||||
sessionDiscardInterval:(NSTimeInterval)discardInterval;
|
sessionDiscardInterval:(NSTimeInterval)discardInterval;
|
||||||
|
|
||||||
- (void)setFetcher:(GTMSessionFetcher *)fetcher
|
- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task;
|
||||||
forTask:(NSURLSessionTask *)task;
|
|
||||||
- (void)removeFetcher:(GTMSessionFetcher *)fetcher;
|
- (void)removeFetcher:(GTMSessionFetcher *)fetcher;
|
||||||
|
|
||||||
// Before using a session, tells the delegate dispatcher to stop the discard timer.
|
// Before using a session, tells the delegate dispatcher to stop the discard timer.
|
||||||
@ -71,7 +72,6 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation GTMSessionFetcherService {
|
@implementation GTMSessionFetcherService {
|
||||||
NSMutableDictionary *_delayedFetchersByHost;
|
NSMutableDictionary *_delayedFetchersByHost;
|
||||||
NSMutableDictionary *_runningFetchersByHost;
|
NSMutableDictionary *_runningFetchersByHost;
|
||||||
@ -106,6 +106,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSDate *_stoppedAllFetchersDate;
|
NSDate *_stoppedAllFetchersDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clang-format likes to cram all @synthesize items onto the fewest lines, rather than one-per.
|
||||||
|
// clang-format off
|
||||||
@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost,
|
@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost,
|
||||||
configuration = _configuration,
|
configuration = _configuration,
|
||||||
configurationBlock = _configurationBlock,
|
configurationBlock = _configurationBlock,
|
||||||
@ -124,7 +126,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
metricsCollectionBlock = _metricsCollectionBlock,
|
metricsCollectionBlock = _metricsCollectionBlock,
|
||||||
properties = _properties,
|
properties = _properties,
|
||||||
unusedSessionTimeout = _unusedSessionTimeout,
|
unusedSessionTimeout = _unusedSessionTimeout,
|
||||||
|
decoratorsPointerArray = _decoratorsPointerArray,
|
||||||
testBlock = _testBlock;
|
testBlock = _testBlock;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
#if GTM_BACKGROUND_TASK_FETCHING
|
#if GTM_BACKGROUND_TASK_FETCHING
|
||||||
@synthesize skipBackgroundTask = _skipBackgroundTask;
|
@synthesize skipBackgroundTask = _skipBackgroundTask;
|
||||||
@ -138,8 +142,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
_maxRunningFetchersPerHost = 10;
|
_maxRunningFetchersPerHost = 10;
|
||||||
_cookieStorageMethod = -1;
|
_cookieStorageMethod = -1;
|
||||||
_unusedSessionTimeout = 60.0;
|
_unusedSessionTimeout = 60.0;
|
||||||
_delegateDispatcher =
|
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
initWithParentService:self
|
||||||
sessionDiscardInterval:_unusedSessionTimeout];
|
sessionDiscardInterval:_unusedSessionTimeout];
|
||||||
_callbackQueue = dispatch_get_main_queue();
|
_callbackQueue = dispatch_get_main_queue();
|
||||||
|
|
||||||
@ -152,10 +156,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
// Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent.
|
// 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
|
// Apps can remove this and get the default system "CFNetwork" useragent by setting the
|
||||||
// fetcher service's userAgent property to nil.
|
// 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);
|
_userAgent = GTMFetcherStandardUserAgentString(nil);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -168,8 +169,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
#pragma mark Generate a new fetcher
|
#pragma mark Generate a new fetcher
|
||||||
|
|
||||||
// Clients may override this method. Clients should not override any other library methods.
|
// Clients may override this method. Clients should not override any other library methods.
|
||||||
- (id)fetcherWithRequest:(NSURLRequest *)request
|
- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass {
|
||||||
fetcherClass:(Class)fetcherClass {
|
|
||||||
GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request
|
GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request
|
||||||
configuration:self.configuration];
|
configuration:self.configuration];
|
||||||
fetcher.callbackQueue = self.callbackQueue;
|
fetcher.callbackQueue = self.callbackQueue;
|
||||||
@ -187,24 +187,25 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
fetcher.retryBlock = self.retryBlock;
|
fetcher.retryBlock = self.retryBlock;
|
||||||
fetcher.maxRetryInterval = self.maxRetryInterval;
|
fetcher.maxRetryInterval = self.maxRetryInterval;
|
||||||
fetcher.minRetryInterval = self.minRetryInterval;
|
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.metricsCollectionBlock = self.metricsCollectionBlock;
|
||||||
}
|
}
|
||||||
fetcher.properties = self.properties;
|
fetcher.properties = self.properties;
|
||||||
fetcher.service = self;
|
fetcher.service = self;
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
if (self.cookieStorageMethod >= 0) {
|
if (self.cookieStorageMethod >= 0) {
|
||||||
[fetcher setCookieStorageMethod:self.cookieStorageMethod];
|
[fetcher setCookieStorageMethod:self.cookieStorageMethod];
|
||||||
}
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
#if GTM_BACKGROUND_TASK_FETCHING
|
#if GTM_BACKGROUND_TASK_FETCHING
|
||||||
fetcher.skipBackgroundTask = self.skipBackgroundTask;
|
fetcher.skipBackgroundTask = self.skipBackgroundTask;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSString *userAgent = self.userAgent;
|
NSString *userAgent = self.userAgent;
|
||||||
if (userAgent.length > 0
|
if (userAgent.length > 0 && [request valueForHTTPHeaderField:@"User-Agent"] == nil) {
|
||||||
&& [request valueForHTTPHeaderField:@"User-Agent"] == nil) {
|
[fetcher setRequestValue:userAgent forHTTPHeaderField:@"User-Agent"];
|
||||||
[fetcher setRequestValue:userAgent
|
|
||||||
forHTTPHeaderField:@"User-Agent"];
|
|
||||||
}
|
}
|
||||||
fetcher.testBlock = self.testBlock;
|
fetcher.testBlock = self.testBlock;
|
||||||
|
|
||||||
@ -212,8 +213,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request {
|
- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request {
|
||||||
return [self fetcherWithRequest:request
|
return [self fetcherWithRequest:request fetcherClass:[GTMSessionFetcher class]];
|
||||||
fetcherClass:[GTMSessionFetcher class]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL {
|
- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL {
|
||||||
@ -225,6 +225,39 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
return [self fetcherWithURL:url];
|
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.
|
// Returns a session for the fetcher's host, or nil.
|
||||||
- (NSURLSession *)session {
|
- (NSURLSession *)session {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
@ -284,8 +317,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
|
|
||||||
#pragma mark Queue Management
|
#pragma mark Queue Management
|
||||||
|
|
||||||
- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher
|
- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host {
|
||||||
forHost:(NSString *)host {
|
|
||||||
// Add to the array of running fetchers for this host, creating the array if needed.
|
// Add to the array of running fetchers for this host, creating the array if needed.
|
||||||
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
||||||
if (runningForHost == nil) {
|
if (runningForHost == nil) {
|
||||||
@ -296,8 +328,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher
|
- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host {
|
||||||
forHost:(NSString *)host {
|
|
||||||
// Add to the array of delayed fetchers for this host, creating the array if needed.
|
// Add to the array of delayed fetchers for this host, creating the array if needed.
|
||||||
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
||||||
if (delayedForHost == nil) {
|
if (delayedForHost == nil) {
|
||||||
@ -345,15 +376,13 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host];
|
||||||
if (runningForHost != nil
|
if (runningForHost != nil && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) {
|
||||||
&& [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) {
|
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher);
|
GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL shouldRunNow = (fetcher.usingBackgroundSession
|
BOOL shouldRunNow = (fetcher.usingBackgroundSession || _maxRunningFetchersPerHost == 0 ||
|
||||||
|| _maxRunningFetchersPerHost == 0
|
_maxRunningFetchersPerHost >
|
||||||
|| _maxRunningFetchersPerHost >
|
|
||||||
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost]);
|
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost]);
|
||||||
if (shouldRunNow) {
|
if (shouldRunNow) {
|
||||||
[self addRunningFetcher:fetcher forHost:host];
|
[self addRunningFetcher:fetcher forHost:host];
|
||||||
@ -373,13 +402,13 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)startFetcher:(GTMSessionFetcher *)fetcher {
|
- (void)startFetcher:(GTMSessionFetcher *)fetcher {
|
||||||
[fetcher beginFetchMayDelay:NO
|
[fetcher beginFetchMayDelay:NO mayAuthorize:YES mayDecorate:YES];
|
||||||
mayAuthorize:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher
|
// 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.
|
// is its own delegate (possibly via proxy) and has no dispatcher.
|
||||||
- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:(GTMSessionFetcher *)fetcher {
|
- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:
|
||||||
|
(GTMSessionFetcher *)fetcher {
|
||||||
GTMSessionCheckNotSynchronized(self);
|
GTMSessionCheckNotSynchronized(self);
|
||||||
|
|
||||||
NSURLSession *fetcherSession = fetcher.session;
|
NSURLSession *fetcherSession = fetcher.session;
|
||||||
@ -388,10 +417,11 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
// If the delegate is non-nil and claims to be a GTMSessionFetcher, there is no dispatcher;
|
// 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
|
// assume the fetcher is the delegate or has been proxied (some third-party frameworks
|
||||||
// are known to swizzle NSURLSession to proxy its delegate).
|
// are known to swizzle NSURLSession to proxy its delegate).
|
||||||
BOOL hasDispatcher = (fetcherDelegate != nil &&
|
BOOL hasDispatcher =
|
||||||
![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]);
|
(fetcherDelegate != nil && ![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]);
|
||||||
if (hasDispatcher) {
|
if (hasDispatcher) {
|
||||||
GTMSESSION_ASSERT_DEBUG([fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]],
|
GTMSESSION_ASSERT_DEBUG(
|
||||||
|
[fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]],
|
||||||
@"Fetcher delegate class: %@", [fetcherDelegate class]);
|
@"Fetcher delegate class: %@", [fetcherDelegate class]);
|
||||||
return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate;
|
return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate;
|
||||||
}
|
}
|
||||||
@ -425,8 +455,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher =
|
GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher =
|
||||||
[self delegateDispatcherForFetcher:fetcher];
|
[self delegateDispatcherForFetcher:fetcher];
|
||||||
if (delegateDispatcher) {
|
if (delegateDispatcher) {
|
||||||
GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession,
|
GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, @"Inappropriate shared session: %@", fetcher);
|
||||||
@"Inappropriate shared session: %@", fetcher);
|
|
||||||
|
|
||||||
// There should already be a session, from this or a previous fetcher.
|
// There should already be a session, from this or a previous fetcher.
|
||||||
//
|
//
|
||||||
@ -435,16 +464,15 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSURLSession *fetcherSession = fetcher.session;
|
NSURLSession *fetcherSession = fetcher.session;
|
||||||
GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher);
|
GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher);
|
||||||
GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession,
|
GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession,
|
||||||
@"Inconsistent session: %@ %@ (shared: %@)",
|
@"Inconsistent session: %@ %@ (shared: %@)", fetcher, fetcherSession,
|
||||||
fetcher, fetcherSession, sharedSession);
|
sharedSession);
|
||||||
|
|
||||||
if (sharedSession != nil && fetcherSession == sharedSession) {
|
if (sharedSession != nil && fetcherSession == sharedSession) {
|
||||||
NSURLSessionTask *task = fetcher.sessionTask;
|
NSURLSessionTask *task = fetcher.sessionTask;
|
||||||
GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher);
|
GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher);
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
[delegateDispatcher setFetcher:fetcher
|
[delegateDispatcher setFetcher:fetcher forTask:task];
|
||||||
forTask:task];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,15 +511,14 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host];
|
||||||
[delayedForHost removeObject:fetcher];
|
[delayedForHost removeObject:fetcher];
|
||||||
|
|
||||||
while (delayedForHost.count > 0
|
while (delayedForHost.count > 0 &&
|
||||||
&& [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]
|
[[self class] numberOfNonBackgroundSessionFetchers:runningForHost] <
|
||||||
< _maxRunningFetchersPerHost) {
|
_maxRunningFetchersPerHost) {
|
||||||
// Start another delayed fetcher running, scanning for the minimum
|
// Start another delayed fetcher running, scanning for the minimum
|
||||||
// priority value, defaulting to FIFO for equal priorities
|
// priority value, defaulting to FIFO for equal priorities
|
||||||
GTMSessionFetcher *nextFetcher = nil;
|
GTMSessionFetcher *nextFetcher = nil;
|
||||||
for (GTMSessionFetcher *delayedFetcher in delayedForHost) {
|
for (GTMSessionFetcher *delayedFetcher in delayedForHost) {
|
||||||
if (nextFetcher == nil
|
if (nextFetcher == nil || delayedFetcher.servicePriority < nextFetcher.servicePriority) {
|
||||||
|| delayedFetcher.servicePriority < nextFetcher.servicePriority) {
|
|
||||||
nextFetcher = delayedFetcher;
|
nextFetcher = delayedFetcher;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -566,9 +593,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
NSMutableArray *allFetchers = [NSMutableArray array];
|
NSMutableArray *allFetchers = [NSMutableArray array];
|
||||||
void (^accumulateFetchers)(id, id, BOOL *) = ^(NSString *host,
|
void (^accumulateFetchers)(id, id, BOOL *) =
|
||||||
NSArray *fetchersForHost,
|
^(NSString *host, NSArray *fetchersForHost, BOOL *stop) {
|
||||||
BOOL *stop) {
|
|
||||||
[allFetchers addObjectsFromArray:fetchersForHost];
|
[allFetchers addObjectsFromArray:fetchersForHost];
|
||||||
};
|
};
|
||||||
[_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers];
|
[_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers];
|
||||||
@ -589,9 +615,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSURL *targetURL = [requestURL absoluteURL];
|
NSURL *targetURL = [requestURL absoluteURL];
|
||||||
|
|
||||||
NSArray *allFetchers = [self issuedFetchers];
|
NSArray *allFetchers = [self issuedFetchers];
|
||||||
NSIndexSet *indexes = [allFetchers indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher,
|
NSIndexSet *indexes = [allFetchers
|
||||||
NSUInteger idx,
|
indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, NSUInteger idx, BOOL *stop) {
|
||||||
BOOL *stop) {
|
|
||||||
NSURL *fetcherURL = [fetcher.request.URL absoluteURL];
|
NSURL *fetcherURL = [fetcher.request.URL absoluteURL];
|
||||||
return [fetcherURL isEqual:targetURL];
|
return [fetcherURL isEqual:targetURL];
|
||||||
}];
|
}];
|
||||||
@ -665,8 +690,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
if (shouldReuse != wasReusing) {
|
if (shouldReuse != wasReusing) {
|
||||||
[self abandonDispatcher];
|
[self abandonDispatcher];
|
||||||
if (shouldReuse) {
|
if (shouldReuse) {
|
||||||
_delegateDispatcher =
|
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
initWithParentService:self
|
||||||
sessionDiscardInterval:_unusedSessionTimeout];
|
sessionDiscardInterval:_unusedSessionTimeout];
|
||||||
} else {
|
} else {
|
||||||
_delegateDispatcher = nil;
|
_delegateDispatcher = nil;
|
||||||
@ -693,8 +718,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
// The old dispatchers may be retained as delegates of any ongoing sessions by those sessions.
|
// The old dispatchers may be retained as delegates of any ongoing sessions by those sessions.
|
||||||
if (_delegateDispatcher) {
|
if (_delegateDispatcher) {
|
||||||
[self abandonDispatcher];
|
[self abandonDispatcher];
|
||||||
_delegateDispatcher =
|
_delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc]
|
||||||
[[GTMSessionFetcherSessionDelegateDispatcher alloc] initWithParentService:self
|
initWithParentService:self
|
||||||
sessionDiscardInterval:_unusedSessionTimeout];
|
sessionDiscardInterval:_unusedSessionTimeout];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,11 +825,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
// Use the fetcher service for the authorization fetches if the auth
|
// Use the fetcher service for the authorization fetches if the auth
|
||||||
// object supports fetcher services
|
// object supports fetcher services
|
||||||
if ([obj respondsToSelector:@selector(setFetcherService:)]) {
|
if ([obj respondsToSelector:@selector(setFetcherService:)]) {
|
||||||
#if GTM_USE_SESSION_FETCHER
|
|
||||||
[obj setFetcherService:self];
|
[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) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -836,7 +857,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
} // @synchronized(self)
|
} // @synchronized(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue {
|
- (void)setCallbackQueue:(dispatch_queue_t)queue {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -844,7 +865,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
} // @synchronized(self)
|
} // @synchronized(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSOperationQueue * GTM_NONNULL_TYPE)sessionDelegateQueue {
|
- (NSOperationQueue *)sessionDelegateQueue {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -852,7 +873,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
} // @synchronized(self)
|
} // @synchronized(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSessionDelegateQueue:(NSOperationQueue * GTM_NULLABLE_TYPE)queue {
|
- (void)setSessionDelegateQueue:(NSOperationQueue *)queue {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -886,8 +907,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSURL *url = [NSURL URLWithString:@"http://example.invalid"];
|
NSURL *url = [NSURL URLWithString:@"http://example.invalid"];
|
||||||
NSHTTPURLResponse *fakedResponse =
|
NSHTTPURLResponse *fakedResponse =
|
||||||
[[NSHTTPURLResponse alloc] initWithURL:url
|
[[NSHTTPURLResponse alloc] initWithURL:url
|
||||||
statusCode:(fakedErrorOrNil ? 500 : 200)
|
statusCode:(fakedErrorOrNil ? 500 : 200)HTTPVersion:@"HTTP/1.1"
|
||||||
HTTPVersion:@"HTTP/1.1"
|
|
||||||
headerFields:nil];
|
headerFields:nil];
|
||||||
return [self mockFetcherServiceWithFakedData:fakedDataOrNil
|
return [self mockFetcherServiceWithFakedData:fakedDataOrNil
|
||||||
fakedResponse:fakedResponse
|
fakedResponse:fakedResponse
|
||||||
@ -904,8 +924,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
#if !GTM_DISABLE_FETCHER_TEST_BLOCK
|
#if !GTM_DISABLE_FETCHER_TEST_BLOCK
|
||||||
GTMSessionFetcherService *service = [[self alloc] init];
|
GTMSessionFetcherService *service = [[self alloc] init];
|
||||||
service.allowedInsecureSchemes = @[ @"http" ];
|
service.allowedInsecureSchemes = @[ @"http" ];
|
||||||
service.testBlock = ^(GTMSessionFetcher *fetcherToTest,
|
service.testBlock =
|
||||||
GTMSessionFetcherTestResponse testResponse) {
|
^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) {
|
||||||
testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil);
|
testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil);
|
||||||
};
|
};
|
||||||
return service;
|
return service;
|
||||||
@ -979,8 +999,7 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
NSTimeInterval _discardInterval;
|
NSTimeInterval _discardInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize discardInterval = _discardInterval,
|
@synthesize discardInterval = _discardInterval, session = _session;
|
||||||
session = _session;
|
|
||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
[self doesNotRecognizeSelector:_cmd];
|
[self doesNotRecognizeSelector:_cmd];
|
||||||
@ -998,9 +1017,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description {
|
- (NSString *)description {
|
||||||
return [NSString stringWithFormat:@"%@ %p %@ %@",
|
return
|
||||||
[self class], self,
|
[NSString stringWithFormat:@"%@ %p %@ %@", [self class], self, _session ?: @"<no session>",
|
||||||
_session ?: @"<no session>",
|
|
||||||
_taskToFetcherMap.count > 0 ? _taskToFetcherMap : @"<no tasks>"];
|
_taskToFetcherMap.count > 0 ? _taskToFetcherMap : @"<no tasks>"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,10 +1195,9 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
//
|
//
|
||||||
// TODO(seh): How do we route this to an appropriate fetcher?
|
// TODO(seh): How do we route this to an appropriate fetcher?
|
||||||
|
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
|
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
|
||||||
GTM_LOG_SESSION_DELEGATE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@",
|
GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class],
|
||||||
[self class], self, session, error);
|
self, session, error);
|
||||||
NSDictionary *localTaskToFetcherMap;
|
NSDictionary *localTaskToFetcherMap;
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
@ -1192,9 +1209,8 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
|
|
||||||
// Any "suspended" tasks may not have received callbacks from NSURLSession when the session
|
// Any "suspended" tasks may not have received callbacks from NSURLSession when the session
|
||||||
// completes; we'll call them now.
|
// completes; we'll call them now.
|
||||||
[localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(NSURLSessionTask *task,
|
[localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^(
|
||||||
GTMSessionFetcher *fetcher,
|
NSURLSessionTask *task, GTMSessionFetcher *fetcher, BOOL *stop) {
|
||||||
BOOL *stop) {
|
|
||||||
if (fetcher.session == session) {
|
if (fetcher.session == session) {
|
||||||
// Our delegate method URLSession:task:didCompleteWithError: will rely on
|
// Our delegate method URLSession:task:didCompleteWithError: will rely on
|
||||||
// _taskToFetcherMap so that should still contain this fetcher.
|
// _taskToFetcherMap so that should still contain this fetcher.
|
||||||
@ -1203,20 +1219,19 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
[self URLSession:session task:task didCompleteWithError:canceledError];
|
[self URLSession:session task:task didCompleteWithError:canceledError];
|
||||||
} else {
|
} else {
|
||||||
GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)",
|
GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", fetcher,
|
||||||
fetcher, fetcher.session, session);
|
fetcher.session, session);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Our tests rely on this notification to know the session discard timer fired.
|
// 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];
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
[nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification
|
[nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification
|
||||||
object:_parentService
|
object:_parentService
|
||||||
userInfo:userInfo];
|
userInfo:userInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - NSURLSessionTaskDelegate
|
#pragma mark - NSURLSessionTaskDelegate
|
||||||
|
|
||||||
// NSURLSessionTaskDelegate protocol methods.
|
// NSURLSessionTaskDelegate protocol methods.
|
||||||
@ -1228,67 +1243,60 @@ NSString *const kGTMSessionFetcherServiceSessionKey
|
|||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||||
newRequest:(NSURLRequest *)request
|
newRequest:(NSURLRequest *)request
|
||||||
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
completionHandler:(void (^)(NSURLRequest *))completionHandler {
|
||||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session
|
||||||
task:task
|
task:task
|
||||||
willPerformHTTPRedirection:response
|
willPerformHTTPRedirection:response
|
||||||
newRequest:request
|
newRequest:request
|
||||||
completionHandler:completionHandler];
|
completionHandler:completionHandler];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||||
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler {
|
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler {
|
||||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session task:task didReceiveChallenge:challenge completionHandler:handler];
|
||||||
task:task
|
|
||||||
didReceiveChallenge:challenge
|
|
||||||
completionHandler:handler];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler {
|
needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler {
|
||||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session task:task needNewBodyStream:handler];
|
||||||
task:task
|
|
||||||
needNewBodyStream:handler];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
didSendBodyData:(int64_t)bytesSent
|
didSendBodyData:(int64_t)bytesSent
|
||||||
totalBytesSent:(int64_t)totalBytesSent
|
totalBytesSent:(int64_t)totalBytesSent
|
||||||
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
|
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
|
||||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session
|
||||||
task:task
|
task:task
|
||||||
didSendBodyData:bytesSent
|
didSendBodyData:bytesSent
|
||||||
totalBytesSent:totalBytesSent
|
totalBytesSent:totalBytesSent
|
||||||
totalBytesExpectedToSend:totalBytesExpectedToSend];
|
totalBytesExpectedToSend:totalBytesExpectedToSend];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
didCompleteWithError:(NSError *)error {
|
didCompleteWithError:(NSError *)error {
|
||||||
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
|
|
||||||
// This is the usual way tasks are removed from the task map.
|
// This is the usual way tasks are removed from the task map.
|
||||||
[self removeTaskFromMap:task];
|
[self removeTaskFromMap:task];
|
||||||
|
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session task:task didCompleteWithError:error];
|
||||||
task:task
|
|
||||||
didCompleteWithError:error];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
task:(NSURLSessionTask *)task
|
task:(NSURLSessionTask *)task
|
||||||
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
|
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];
|
id<NSURLSessionTaskDelegate> fetcher = [self fetcherForTask:task];
|
||||||
[fetcher URLSession:session task:task didFinishCollectingMetrics:metrics];
|
[fetcher URLSession:session task:task didFinishCollectingMetrics:metrics];
|
||||||
}
|
}
|
||||||
@ -1297,7 +1305,7 @@ didCompleteWithError:(NSError *)error {
|
|||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
dataTask:(NSURLSessionDataTask *)dataTask
|
dataTask:(NSURLSessionDataTask *)dataTask
|
||||||
didReceiveResponse:(NSURLResponse *)response
|
didReceiveResponse:(NSURLResponse *)response
|
||||||
completionHandler:(void (^)(NSURLSessionResponseDisposition))handler {
|
completionHandler:(void (^)(NSURLSessionResponseDisposition))handler {
|
||||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session
|
||||||
@ -1308,7 +1316,7 @@ didReceiveResponse:(NSURLResponse *)response
|
|||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
dataTask:(NSURLSessionDataTask *)dataTask
|
dataTask:(NSURLSessionDataTask *)dataTask
|
||||||
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
||||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||||
GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask);
|
GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask);
|
||||||
[self removeTaskFromMap:dataTask];
|
[self removeTaskFromMap:dataTask];
|
||||||
@ -1318,18 +1326,14 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
|
|||||||
[self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask];
|
[self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask];
|
||||||
}
|
}
|
||||||
|
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask];
|
||||||
dataTask:dataTask
|
|
||||||
didBecomeDownloadTask:downloadTask];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
dataTask:(NSURLSessionDataTask *)dataTask
|
dataTask:(NSURLSessionDataTask *)dataTask
|
||||||
didReceiveData:(NSData *)data {
|
didReceiveData:(NSData *)data {
|
||||||
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
id<NSURLSessionDataDelegate> fetcher = [self fetcherForTask:dataTask];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session dataTask:dataTask didReceiveData:data];
|
||||||
dataTask:dataTask
|
|
||||||
didReceiveData:data];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
@ -1347,30 +1351,28 @@ didBecomeDownloadTask:downloadTask];
|
|||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||||
didFinishDownloadingToURL:(NSURL *)location {
|
didFinishDownloadingToURL:(NSURL *)location {
|
||||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
|
||||||
downloadTask:downloadTask
|
|
||||||
didFinishDownloadingToURL:location];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||||
didWriteData:(int64_t)bytesWritten
|
didWriteData:(int64_t)bytesWritten
|
||||||
totalBytesWritten:(int64_t)totalWritten
|
totalBytesWritten:(int64_t)totalWritten
|
||||||
totalBytesExpectedToWrite:(int64_t)totalExpected {
|
totalBytesExpectedToWrite:(int64_t)totalExpected {
|
||||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session
|
||||||
downloadTask:downloadTask
|
downloadTask:downloadTask
|
||||||
didWriteData:bytesWritten
|
didWriteData:bytesWritten
|
||||||
totalBytesWritten:totalWritten
|
totalBytesWritten:totalWritten
|
||||||
totalBytesExpectedToWrite:totalExpected];
|
totalBytesExpectedToWrite:totalExpected];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession *)session
|
- (void)URLSession:(NSURLSession *)session
|
||||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||||
didResumeAtOffset:(int64_t)fileOffset
|
didResumeAtOffset:(int64_t)fileOffset
|
||||||
expectedTotalBytes:(int64_t)expectedTotalBytes {
|
expectedTotalBytes:(int64_t)expectedTotalBytes {
|
||||||
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
id<NSURLSessionDownloadDelegate> fetcher = [self fetcherForTask:downloadTask];
|
||||||
[fetcher URLSession:session
|
[fetcher URLSession:session
|
||||||
downloadTask:downloadTask
|
downloadTask:downloadTask
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
#import "GTMSessionFetcher.h"
|
#import "GTMSessionFetcher.h"
|
||||||
#import "GTMSessionFetcherService.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.
|
// The value to use for file size parameters when the file size is not yet known.
|
||||||
extern int64_t const kGTMSessionUploadFetcherUnknownFileSize;
|
extern int64_t const kGTMSessionUploadFetcherUnknownFileSize;
|
||||||
@ -68,24 +68,23 @@ extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification;
|
|||||||
// to its proper value.
|
// to its proper value.
|
||||||
//
|
//
|
||||||
// Pass nil as the data (and optionally an NSError) for a failure.
|
// 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,
|
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
|
// 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
|
// 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.
|
// of data in the file being uploaded.
|
||||||
typedef void (^GTMSessionUploadFetcherDataProvider)(int64_t offset, int64_t length,
|
typedef void (^GTMSessionUploadFetcherDataProvider)(
|
||||||
GTMSessionUploadFetcherDataProviderResponse response);
|
int64_t offset, int64_t length, GTMSessionUploadFetcherDataProviderResponse response);
|
||||||
|
|
||||||
// Block to be notified about the final status of the cancellation request started in stopFetching.
|
// 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
|
// |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
|
// going to send a cancel request. If |fetcher| is provided, the other parameters correspond to the
|
||||||
// completion handler of the cancellation request fetcher.
|
// completion handler of the cancellation request fetcher.
|
||||||
typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
typedef void (^GTMSessionUploadFetcherCancellationHandler)(GTMSessionFetcher *_Nullable fetcher,
|
||||||
GTMSessionFetcher * GTM_NULLABLE_TYPE fetcher,
|
NSData *_Nullable data,
|
||||||
NSData * GTM_NULLABLE_TYPE data,
|
NSError *_Nullable error);
|
||||||
NSError * GTM_NULLABLE_TYPE error);
|
|
||||||
|
|
||||||
@interface GTMSessionUploadFetcher : GTMSessionFetcher
|
@interface GTMSessionUploadFetcher : GTMSessionFetcher
|
||||||
|
|
||||||
@ -100,37 +99,37 @@ typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
|||||||
+ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request
|
+ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request
|
||||||
uploadMIMEType:(NSString *)uploadMIMEType
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
chunkSize:(int64_t)chunkSize
|
||||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil;
|
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||||
|
|
||||||
// Allows cellular access.
|
// Allows cellular access.
|
||||||
+ (instancetype)uploadFetcherWithLocation:(NSURL * GTM_NULLABLE_TYPE)uploadLocationURL
|
+ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL
|
||||||
uploadMIMEType:(NSString *)uploadMIMEType
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
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
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
chunkSize:(int64_t)chunkSize
|
||||||
allowsCellularAccess:(BOOL)allowsCellularAccess
|
allowsCellularAccess:(BOOL)allowsCellularAccess
|
||||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil;
|
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil;
|
||||||
|
|
||||||
// Allows dataProviders for files of unknown length. Pass kGTMSessionUploadFetcherUnknownFileSize as
|
// Allows dataProviders for files of unknown length. Pass kGTMSessionUploadFetcherUnknownFileSize as
|
||||||
// |fullLength| if the length is unknown.
|
// |fullLength| if the length is unknown.
|
||||||
- (void)setUploadDataLength:(int64_t)fullLength
|
- (void)setUploadDataLength:(int64_t)fullLength
|
||||||
provider:(GTM_NULLABLE GTMSessionUploadFetcherDataProvider)block;
|
provider:(nullable GTMSessionUploadFetcherDataProvider)block;
|
||||||
|
|
||||||
+ (NSArray *)uploadFetchersForBackgroundSessions;
|
+ (NSArray *)uploadFetchersForBackgroundSessions;
|
||||||
+ (GTM_NULLABLE instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier;
|
+ (nullable instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier;
|
||||||
|
|
||||||
- (void)pauseFetching;
|
- (void)pauseFetching;
|
||||||
- (void)resumeFetching;
|
- (void)resumeFetching;
|
||||||
- (BOOL)isPaused;
|
- (BOOL)isPaused;
|
||||||
|
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSURL *uploadLocationURL;
|
@property(atomic, strong, nullable) NSURL *uploadLocationURL;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSData *uploadData;
|
@property(atomic, strong, nullable) NSData *uploadData;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSURL *uploadFileURL;
|
@property(atomic, strong, nullable) NSURL *uploadFileURL;
|
||||||
@property(atomic, strong, GTM_NULLABLE) NSFileHandle *uploadFileHandle;
|
@property(atomic, strong, nullable) NSFileHandle *uploadFileHandle;
|
||||||
@property(atomic, copy, readonly, GTM_NULLABLE) GTMSessionUploadFetcherDataProvider uploadDataProvider;
|
@property(atomic, copy, readonly, nullable) GTMSessionUploadFetcherDataProvider uploadDataProvider;
|
||||||
@property(atomic, copy) NSString *uploadMIMEType;
|
@property(atomic, copy) NSString *uploadMIMEType;
|
||||||
@property(atomic, readonly, assign) int64_t chunkSize;
|
@property(atomic, readonly, assign) int64_t chunkSize;
|
||||||
@property(atomic, readonly, assign) int64_t currentOffset;
|
@property(atomic, readonly, assign) int64_t currentOffset;
|
||||||
@ -138,14 +137,14 @@ typedef void (^GTMSessionUploadFetcherCancellationHandler)(
|
|||||||
@property(atomic, readonly, assign) BOOL allowsCellularAccess;
|
@property(atomic, readonly, assign) BOOL allowsCellularAccess;
|
||||||
|
|
||||||
// The fetcher for the current data chunk, if any
|
// 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
|
// The active fetcher is the current chunk fetcher, or the upload fetcher itself
|
||||||
// if no chunk fetcher has yet been created.
|
// if no chunk fetcher has yet been created.
|
||||||
@property(atomic, readonly) GTMSessionFetcher *activeFetcher;
|
@property(atomic, readonly) GTMSessionFetcher *activeFetcher;
|
||||||
|
|
||||||
// The last request made by an active fetcher. Useful for testing.
|
// 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.
|
// The status code from the most recently-completed fetch.
|
||||||
@property(atomic, assign) NSInteger statusCode;
|
@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
|
// 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
|
// cleared by stopFetching. It will instead clear itself after it is invoked or if the completion
|
||||||
// has occured before stopFetching is called.
|
// has occured before stopFetching is called.
|
||||||
@property(atomic, copy, GTM_NULLABLE) GTMSessionUploadFetcherCancellationHandler
|
@property(atomic, copy, nullable) GTMSessionUploadFetcherCancellationHandler cancellationHandler;
|
||||||
cancellationHandler;
|
|
||||||
|
|
||||||
// Exposed for testing only.
|
// Exposed for testing only.
|
||||||
@property(atomic, readonly, GTM_NULLABLE) dispatch_queue_t delegateCallbackQueue;
|
@property(atomic, readonly, nullable) dispatch_queue_t delegateCallbackQueue;
|
||||||
@property(atomic, readonly, GTM_NULLABLE) GTMSessionFetcherCompletionHandler delegateCompletionHandler;
|
@property(atomic, readonly, nullable) GTMSessionFetcherCompletionHandler delegateCompletionHandler;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods)
|
@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods)
|
||||||
|
|
||||||
@property(readonly, GTM_NULLABLE) GTMSessionUploadFetcher *parentUploadFetcher;
|
@property(readonly, nullable) GTMSessionUploadFetcher *parentUploadFetcher;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
GTM_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
326
Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m
generated
326
Pods/GTMSessionFetcher/Source/GTMSessionUploadFetcher.m
generated
@ -19,6 +19,12 @@
|
|||||||
|
|
||||||
#import "GTMSessionUploadFetcher.h"
|
#import "GTMSessionUploadFetcher.h"
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX && GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
|
||||||
|
// To reconnect background sessions on Mac outside +load requires importing and linking
|
||||||
|
// AppKit to access the NSApplicationDidFinishLaunching symbol.
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk";
|
static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk";
|
||||||
static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL";
|
static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL";
|
||||||
static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen";
|
static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen";
|
||||||
@ -28,7 +34,8 @@ static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"
|
|||||||
static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset";
|
static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset";
|
||||||
static NSString *const kGTMSessionIdentifierUploadAllowsCellularAccess = @"_upAllowsCellularAccess";
|
static NSString *const kGTMSessionIdentifierUploadAllowsCellularAccess = @"_upAllowsCellularAccess";
|
||||||
|
|
||||||
static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = @"X-Goog-Upload-Chunk-Granularity";
|
static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity =
|
||||||
|
@"X-Goog-Upload-Chunk-Granularity";
|
||||||
static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command";
|
static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command";
|
||||||
static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length";
|
static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length";
|
||||||
static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type";
|
static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type";
|
||||||
@ -47,9 +54,11 @@ int64_t const kGTMSessionUploadFetcherUnknownFileSize = -1;
|
|||||||
int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX;
|
int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX;
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS
|
int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize =
|
||||||
|
10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS
|
||||||
#else
|
#else
|
||||||
int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = 100 * 1024 * 1024; // 100 MB for macOS
|
int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize =
|
||||||
|
100 * 1024 * 1024; // 100 MB for macOS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) {
|
typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) {
|
||||||
@ -93,7 +102,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
@property(atomic, readwrite, assign) int64_t currentOffset;
|
@property(atomic, readwrite, assign) int64_t currentOffset;
|
||||||
|
|
||||||
// Internal properties.
|
// Internal properties.
|
||||||
@property(strong, atomic, GTM_NULLABLE) GTMSessionFetcher *fetcherInFlight; // Synchronized on self.
|
@property(strong, atomic, nullable) GTMSessionFetcher *fetcherInFlight; // Synchronized on self.
|
||||||
|
|
||||||
@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating;
|
@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating;
|
||||||
@property(assign, atomic) BOOL shouldInitiateOffsetQuery;
|
@property(assign, atomic) BOOL shouldInitiateOffsetQuery;
|
||||||
@ -149,7 +158,30 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (void)load {
|
+ (void)load {
|
||||||
|
#if GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_IPHONE
|
||||||
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
|
[nc addObserver:self
|
||||||
|
selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:)
|
||||||
|
name:UIApplicationDidFinishLaunchingNotification
|
||||||
|
object:nil];
|
||||||
|
#elif GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_OSX
|
||||||
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
|
[nc addObserver:self
|
||||||
|
selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:)
|
||||||
|
name:NSApplicationDidFinishLaunchingNotification
|
||||||
|
object:nil];
|
||||||
|
#else
|
||||||
[self uploadFetchersForBackgroundSessions];
|
[self uploadFetchersForBackgroundSessions];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)reconnectFetchersForBackgroundSessionsOnAppLaunch:(NSNotification *)notification {
|
||||||
|
// Give all other app-did-launch handlers a chance to complete before
|
||||||
|
// reconnecting the fetchers. Not doing this may lead to reconnecting
|
||||||
|
// before the app delegate has a chance to run.
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self uploadFetchersForBackgroundSessions];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request
|
+ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request
|
||||||
@ -165,10 +197,10 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
return fetcher;
|
return fetcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)uploadFetcherWithLocation:(NSURL *GTM_NULLABLE_TYPE)uploadLocationURL
|
+ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL
|
||||||
uploadMIMEType:(NSString *)uploadMIMEType
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
chunkSize:(int64_t)chunkSize
|
||||||
fetcherService:(GTM_NULLABLE GTMSessionFetcherService *)fetcherServiceOrNil {
|
fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil {
|
||||||
return [self uploadFetcherWithLocation:uploadLocationURL
|
return [self uploadFetcherWithLocation:uploadLocationURL
|
||||||
uploadMIMEType:uploadMIMEType
|
uploadMIMEType:uploadMIMEType
|
||||||
chunkSize:chunkSize
|
chunkSize:chunkSize
|
||||||
@ -176,7 +208,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
fetcherService:fetcherServiceOrNil];
|
fetcherService:fetcherServiceOrNil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)uploadFetcherWithLocation:(NSURL *GTM_NULLABLE_TYPE)uploadLocationURL
|
+ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL
|
||||||
uploadMIMEType:(NSString *)uploadMIMEType
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
chunkSize:(int64_t)chunkSize
|
||||||
allowsCellularAccess:(BOOL)allowsCellularAccess
|
allowsCellularAccess:(BOOL)allowsCellularAccess
|
||||||
@ -218,8 +250,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
NSURL *uploadLocationURL =
|
NSURL *uploadLocationURL =
|
||||||
uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil;
|
uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil;
|
||||||
|
|
||||||
NSString *uploadMIMEType =
|
NSString *uploadMIMEType = metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey];
|
||||||
metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey];
|
|
||||||
int64_t uploadChunkSize =
|
int64_t uploadChunkSize =
|
||||||
[metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue];
|
[metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue];
|
||||||
if (uploadChunkSize <= 0) {
|
if (uploadChunkSize <= 0) {
|
||||||
@ -234,8 +265,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
|
|
||||||
GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength,
|
GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength,
|
||||||
@"CurrentOffset (%lld) exceeds UploadFileSize (%lld)",
|
@"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", currentOffset,
|
||||||
currentOffset, uploadFileLength);
|
uploadFileLength);
|
||||||
if (currentOffset > uploadFileLength) return nil;
|
if (currentOffset > uploadFileLength) return nil;
|
||||||
|
|
||||||
GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL
|
GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL
|
||||||
@ -260,8 +291,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// Internal utility method for instantiating fetchers
|
// Internal utility method for instantiating fetchers
|
||||||
GTMSessionUploadFetcher *fetcher;
|
GTMSessionUploadFetcher *fetcher;
|
||||||
if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) {
|
if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) {
|
||||||
fetcher = [fetcherService fetcherWithRequest:request
|
fetcher = [fetcherService fetcherWithRequest:request fetcherClass:self];
|
||||||
fetcherClass:self];
|
|
||||||
} else {
|
} else {
|
||||||
fetcher = [self fetcherWithRequest:request];
|
fetcher = [self fetcherWithRequest:request];
|
||||||
}
|
}
|
||||||
@ -319,7 +349,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
if (sessionIdentifierMetadata == nil) {
|
if (sessionIdentifierMetadata == nil) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue]) {
|
if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey]
|
||||||
|
boolValue]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GTMSessionUploadFetcher *uploadFetcher =
|
GTMSessionUploadFetcher *uploadFetcher =
|
||||||
@ -337,8 +368,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
[fetcher completionHandlerWithTarget:uploadFetcher
|
[fetcher completionHandlerWithTarget:uploadFetcher
|
||||||
didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)];
|
didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)];
|
||||||
|
|
||||||
GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@",
|
GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", [self class],
|
||||||
[self class], uploadFetcher, fetcher);
|
uploadFetcher, fetcher);
|
||||||
}
|
}
|
||||||
return uploadFetchers;
|
return uploadFetchers;
|
||||||
}
|
}
|
||||||
@ -445,7 +476,6 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)setUploadMIMEType:(NSString *)uploadMIMEType {
|
- (void)setUploadMIMEType:(NSString *)uploadMIMEType {
|
||||||
GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly");
|
GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly");
|
||||||
// (and uploadMIMEType, chunksize, currentOffset)
|
// (and uploadMIMEType, chunksize, currentOffset)
|
||||||
@ -484,9 +514,9 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
int hasFileURL = (_uploadFileURL != nil) ? 1 : 0;
|
int hasFileURL = (_uploadFileURL != nil) ? 1 : 0;
|
||||||
int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0;
|
int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0;
|
||||||
int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider;
|
int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider;
|
||||||
#pragma unused(numberOfSources)
|
#pragma unused(numberOfSources)
|
||||||
GTMSESSION_ASSERT_DEBUG(numberOfSources == 1,
|
GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, @"Need just one upload source (%d)",
|
||||||
@"Need just one upload source (%d)", numberOfSources);
|
numberOfSources);
|
||||||
} // @synchronized(self)
|
} // @synchronized(self)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -500,8 +530,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
[mutableRequest setValue:kGTMSessionXGoogUploadProtocolResumable
|
[mutableRequest setValue:kGTMSessionXGoogUploadProtocolResumable
|
||||||
forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol];
|
forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol];
|
||||||
[mutableRequest setValue:@"start"
|
[mutableRequest setValue:@"start" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
||||||
forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
|
||||||
[mutableRequest setValue:_uploadMIMEType
|
[mutableRequest setValue:_uploadMIMEType
|
||||||
forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType];
|
forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType];
|
||||||
[mutableRequest setValue:@([self fullUploadLength]).stringValue
|
[mutableRequest setValue:@([self fullUploadLength]).stringValue
|
||||||
@ -517,8 +546,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// we need to make a bug fix in the client that the server can recognize.
|
// we need to make a bug fix in the client that the server can recognize.
|
||||||
NSString *const kUserAgentStub = @"(GTMSUF/1)";
|
NSString *const kUserAgentStub = @"(GTMSUF/1)";
|
||||||
NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"];
|
NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"];
|
||||||
if (userAgent == nil
|
if (userAgent == nil || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) {
|
||||||
|| [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) {
|
|
||||||
if (userAgent.length == 0) {
|
if (userAgent.length == 0) {
|
||||||
userAgent = GTMFetcherStandardUserAgentString(nil);
|
userAgent = GTMFetcherStandardUserAgentString(nil);
|
||||||
}
|
}
|
||||||
@ -528,7 +556,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
[self setRequest:mutableRequest];
|
[self setRequest:mutableRequest];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLocationURL:(NSURL *GTM_NULLABLE_TYPE)location
|
- (void)setLocationURL:(nullable NSURL *)location
|
||||||
uploadMIMEType:(NSString *)uploadMIMEType
|
uploadMIMEType:(NSString *)uploadMIMEType
|
||||||
chunkSize:(int64_t)chunkSize
|
chunkSize:(int64_t)chunkSize
|
||||||
allowsCellularAccess:(BOOL)allowsCellularAccess {
|
allowsCellularAccess:(BOOL)allowsCellularAccess {
|
||||||
@ -580,8 +608,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
error:&valueError]) {
|
error:&valueError]) {
|
||||||
_uploadFileLength = filesizeNum.longLongValue;
|
_uploadFileLength = filesizeNum.longLongValue;
|
||||||
} else {
|
} else {
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@",
|
GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", valueError,
|
||||||
valueError, _uploadFileURL.path);
|
_uploadFileURL.path);
|
||||||
_uploadFileLength = 0;
|
_uploadFileLength = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -612,12 +640,12 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
int64_t dataLength = (int64_t)uploadData.length;
|
int64_t dataLength = (int64_t)uploadData.length;
|
||||||
// Ensure our range is valid. b/18007814
|
// Ensure our range is valid. b/18007814
|
||||||
if (offset + length > dataLength) {
|
if (offset + length > dataLength) {
|
||||||
NSString *errorMessage = [NSString stringWithFormat:
|
NSString *errorMessage = [NSString
|
||||||
|
stringWithFormat:
|
||||||
@"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld",
|
@"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld",
|
||||||
offset, length, dataLength];
|
offset, length, dataLength];
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
||||||
response(nil,
|
response(nil, kGTMSessionUploadFetcherUnknownFileSize,
|
||||||
kGTMSessionUploadFetcherUnknownFileSize,
|
|
||||||
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -625,12 +653,10 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
@try {
|
@try {
|
||||||
resultData = [uploadData subdataWithRange:range];
|
resultData = [uploadData subdataWithRange:range];
|
||||||
}
|
} @catch (NSException *exception) {
|
||||||
@catch (NSException *exception) {
|
|
||||||
NSString *errorMessage = exception.description;
|
NSString *errorMessage = exception.description;
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
||||||
response(nil,
|
response(nil, kGTMSessionUploadFetcherUnknownFileSize,
|
||||||
kGTMSessionUploadFetcherUnknownFileSize,
|
|
||||||
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -667,8 +693,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
@try {
|
@try {
|
||||||
[fileHandle seekToFileOffset:(unsigned long long)offset];
|
[fileHandle seekToFileOffset:(unsigned long long)offset];
|
||||||
resultData = [fileHandle readDataOfLength:(NSUInteger)length];
|
resultData = [fileHandle readDataOfLength:(NSUInteger)length];
|
||||||
}
|
} @catch (NSException *exception) {
|
||||||
@catch (NSException *exception) {
|
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception);
|
GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception);
|
||||||
error = [self uploadChunkUnavailableErrorWithDescription:exception.description];
|
error = [self uploadChunkUnavailableErrorWithDescription:exception.description];
|
||||||
}
|
}
|
||||||
@ -719,8 +744,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
hasFileSize ? fileSizeNum : @"unknown", error);
|
hasFileSize ? fileSizeNum : @"unknown", error);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL
|
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL error:&error];
|
||||||
error:&error];
|
|
||||||
if (fileHandle != nil) {
|
if (fileHandle != nil) {
|
||||||
[self generateChunkSubdataFromFileHandle:fileHandle
|
[self generateChunkSubdataFromFileHandle:fileHandle
|
||||||
offset:offset
|
offset:offset
|
||||||
@ -733,12 +757,12 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
} else {
|
} else {
|
||||||
// Successfully created an NSData by memory-mapping the file.
|
// Successfully created an NSData by memory-mapping the file.
|
||||||
if ((NSUInteger)(offset + length) > mappedData.length) {
|
if ((NSUInteger)(offset + length) > mappedData.length) {
|
||||||
NSString *errorMessage = [NSString stringWithFormat:
|
NSString *errorMessage = [NSString
|
||||||
@"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld\texpected UploadLength: %lld",
|
stringWithFormat:@"Range invalid for upload data. offset: %lld\tlength: "
|
||||||
|
@"%lld\tdataLength: %lld\texpected UploadLength: %lld",
|
||||||
offset, length, (long long)mappedData.length, fullUploadLength];
|
offset, length, (long long)mappedData.length, fullUploadLength];
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage);
|
||||||
response(nil,
|
response(nil, kGTMSessionUploadFetcherUnknownFileSize,
|
||||||
kGTMSessionUploadFetcherUnknownFileSize,
|
|
||||||
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
[self uploadChunkUnavailableErrorWithDescription:errorMessage]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -756,7 +780,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description {
|
- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description {
|
||||||
// The description in the userInfo is intended as a clue to programmers, not
|
// The description in the userInfo is intended as a clue to programmers, not
|
||||||
// for client code to examine or rely on.
|
// for client code to examine or rely on.
|
||||||
NSDictionary *userInfo = @{ @"description" : description };
|
NSDictionary *userInfo = @{@"description" : description};
|
||||||
return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain
|
return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain
|
||||||
code:GTMSessionFetcherErrorUploadChunkUnavailable
|
code:GTMSessionFetcherErrorUploadChunkUnavailable
|
||||||
userInfo:userInfo];
|
userInfo:userInfo];
|
||||||
@ -796,7 +820,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDelegateCallbackQueue:(dispatch_queue_t GTM_NULLABLE_TYPE)queue {
|
- (void)setDelegateCallbackQueue:(nullable dispatch_queue_t)queue {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -804,7 +828,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (dispatch_queue_t GTM_NULLABLE_TYPE)delegateCallbackQueue {
|
- (nullable dispatch_queue_t)delegateCallbackQueue {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -820,7 +844,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (GTMSessionFetcher * GTM_NULLABLE_TYPE)chunkFetcher {
|
- (nullable GTMSessionFetcher *)chunkFetcher {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -828,7 +852,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setChunkFetcher:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher {
|
- (void)setChunkFetcher:(nullable GTMSessionFetcher *)fetcher {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -836,7 +860,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFetcherInFlight:(GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcher {
|
- (void)setFetcherInFlight:(nullable GTMSessionFetcher *)fetcher {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -844,7 +868,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (GTMSessionFetcher * GTM_NULLABLE_TYPE)fetcherInFlight {
|
- (nullable GTMSessionFetcher *)fetcherInFlight {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -852,8 +876,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCancellationHandler:(GTMSessionUploadFetcherCancellationHandler GTM_NULLABLE_TYPE)
|
- (void)setCancellationHandler:
|
||||||
cancellationHandler {
|
(nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -861,7 +885,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (GTMSessionUploadFetcherCancellationHandler GTM_NULLABLE_TYPE)cancellationHandler {
|
- (nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
|
|
||||||
@ -919,9 +943,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
[self beginChunkFetches];
|
[self beginChunkFetches];
|
||||||
} else {
|
} else {
|
||||||
if ([self retryTimer] == nil) {
|
if ([self retryTimer] == nil) {
|
||||||
[self invokeFinalCallbackWithData:nil
|
[self invokeFinalCallbackWithData:nil error:error shouldInvalidateLocation:YES];
|
||||||
error:error
|
|
||||||
shouldInvalidateLocation:YES];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -930,16 +952,15 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// is never used, so at this point we call the user's actual completion
|
// is never used, so at this point we call the user's actual completion
|
||||||
// block.
|
// block.
|
||||||
if (!hasTestBlock) {
|
if (!hasTestBlock) {
|
||||||
[self invokeFinalCallbackWithData:data
|
[self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES];
|
||||||
error:error
|
|
||||||
shouldInvalidateLocation:YES];
|
|
||||||
} else {
|
} else {
|
||||||
// There was a test block, so we won't do chunk fetches, but we simulate obtaining
|
// There was a test block, so we won't do chunk fetches, but we simulate obtaining
|
||||||
// the data to be uploaded from the upload data provider block or the file handle,
|
// the data to be uploaded from the upload data provider block or the file handle,
|
||||||
// and then call back.
|
// and then call back.
|
||||||
[self generateChunkSubdataWithOffset:0
|
[self generateChunkSubdataWithOffset:0
|
||||||
length:[self fullUploadLength]
|
length:[self fullUploadLength]
|
||||||
response:^(NSData *generateData, int64_t fullUploadLength, NSError *generateError) {
|
response:^(NSData *generateData, int64_t fullUploadLength,
|
||||||
|
NSError *generateError) {
|
||||||
[self invokeFinalCallbackWithData:data
|
[self invokeFinalCallbackWithData:data
|
||||||
error:error
|
error:error
|
||||||
shouldInvalidateLocation:YES];
|
shouldInvalidateLocation:YES];
|
||||||
@ -961,9 +982,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// resumable request/response.
|
// resumable request/response.
|
||||||
if (self.downloadedData.length > 0) {
|
if (self.downloadedData.length > 0) {
|
||||||
NSData *downloadedData = self.downloadedData;
|
NSData *downloadedData = self.downloadedData;
|
||||||
NSString *str = [[NSString alloc] initWithData:downloadedData
|
NSString *str = [[NSString alloc] initWithData:downloadedData encoding:NSUTF8StringEncoding];
|
||||||
encoding:NSUTF8StringEncoding];
|
#pragma unused(str)
|
||||||
#pragma unused(str)
|
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str);
|
GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -976,7 +996,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
GTMSessionUploadFetcherStatus uploadStatus =
|
GTMSessionUploadFetcherStatus uploadStatus =
|
||||||
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
||||||
GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown,
|
GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown,
|
||||||
@"beginChunkFetches has unexpected upload status for headers %@", responseHeaders);
|
@"beginChunkFetches has unexpected upload status for headers %@",
|
||||||
|
responseHeaders);
|
||||||
|
|
||||||
BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled);
|
BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled);
|
||||||
|
|
||||||
@ -985,26 +1006,24 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
if (isPrematureStop || !hasUploadLocation) {
|
if (isPrematureStop || !hasUploadLocation) {
|
||||||
GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@",
|
GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@",
|
||||||
[responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], uploadLocationURLStr);
|
[responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus],
|
||||||
|
uploadLocationURLStr);
|
||||||
// We cannot continue since we do not know the location to use
|
// We cannot continue since we do not know the location to use
|
||||||
// as our upload destination.
|
// as our upload destination.
|
||||||
NSDictionary *userInfo = nil;
|
NSDictionary *userInfo = nil;
|
||||||
NSData *downloadedData = self.downloadedData;
|
NSData *downloadedData = self.downloadedData;
|
||||||
if (downloadedData.length > 0) {
|
if (downloadedData.length > 0) {
|
||||||
userInfo = @{ kGTMSessionFetcherStatusDataKey : downloadedData };
|
userInfo = @{kGTMSessionFetcherStatusDataKey : downloadedData};
|
||||||
}
|
}
|
||||||
NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo];
|
NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo];
|
||||||
[self invokeFinalCallbackWithData:nil
|
[self invokeFinalCallbackWithData:nil error:failureError shouldInvalidateLocation:YES];
|
||||||
error:failureError
|
|
||||||
shouldInvalidateLocation:YES];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr];
|
self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr];
|
||||||
|
|
||||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
[nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification
|
[nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification object:self];
|
||||||
object:self];
|
|
||||||
|
|
||||||
// we've now sent all of the initial post body data, so we need to include
|
// we've now sent all of the initial post body data, so we need to include
|
||||||
// its size in future progress indicator callbacks
|
// its size in future progress indicator callbacks
|
||||||
@ -1101,18 +1120,16 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// use the properties in each chunk fetcher
|
// use the properties in each chunk fetcher
|
||||||
NSDictionary *props = [self properties];
|
NSDictionary *props = [self properties];
|
||||||
|
|
||||||
[self uploadNextChunkWithOffset:offset
|
[self uploadNextChunkWithOffset:offset fetcherProperties:props];
|
||||||
fetcherProperties:props];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props {
|
- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props {
|
||||||
GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props
|
GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES];
|
||||||
isQueryFetch:YES];
|
|
||||||
queryFetcher.bodyData = [NSData data];
|
queryFetcher.bodyData = [NSData data];
|
||||||
|
|
||||||
NSString *originalComment = self.comment;
|
NSString *originalComment = self.comment;
|
||||||
[queryFetcher setCommentWithFormat:@"%@ (query offset)",
|
[queryFetcher
|
||||||
originalComment ? originalComment : @"upload"];
|
setCommentWithFormat:@"%@ (query offset)", originalComment ? originalComment : @"upload"];
|
||||||
|
|
||||||
[queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
[queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
||||||
|
|
||||||
@ -1132,7 +1149,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
GTMSessionUploadFetcherStatus uploadStatus =
|
GTMSessionUploadFetcherStatus uploadStatus =
|
||||||
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
||||||
GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil,
|
GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil,
|
||||||
@"query fetcher completion has unexpected upload status for headers %@", responseHeaders);
|
@"query fetcher completion has unexpected upload status for headers %@",
|
||||||
|
responseHeaders);
|
||||||
|
|
||||||
if (error == nil) {
|
if (error == nil) {
|
||||||
sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived];
|
sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived];
|
||||||
@ -1141,7 +1159,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
(uploadStatus == kStatusActive && sizeReceivedHeader == nil)) {
|
(uploadStatus == kStatusActive && sizeReceivedHeader == nil)) {
|
||||||
NSDictionary *userInfo = nil;
|
NSDictionary *userInfo = nil;
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
userInfo = @{ kGTMSessionFetcherStatusDataKey : data };
|
userInfo = @{kGTMSessionFetcherStatusDataKey : data};
|
||||||
}
|
}
|
||||||
error = [self prematureFailureErrorWithUserInfo:userInfo];
|
error = [self prematureFailureErrorWithUserInfo:userInfo];
|
||||||
}
|
}
|
||||||
@ -1169,13 +1187,12 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_isCancelInFlight = YES;
|
_isCancelInFlight = YES;
|
||||||
}
|
}
|
||||||
GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props
|
GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES];
|
||||||
isQueryFetch:YES];
|
|
||||||
cancelFetcher.bodyData = [NSData data];
|
cancelFetcher.bodyData = [NSData data];
|
||||||
|
|
||||||
NSString *originalComment = self.comment;
|
NSString *originalComment = self.comment;
|
||||||
[cancelFetcher setCommentWithFormat:@"%@ (cancel)",
|
[cancelFetcher
|
||||||
originalComment ? originalComment : @"upload"];
|
setCommentWithFormat:@"%@ (cancel)", originalComment ? originalComment : @"upload"];
|
||||||
|
|
||||||
[cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
[cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand];
|
||||||
|
|
||||||
@ -1193,8 +1210,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)uploadNextChunkWithOffset:(int64_t)offset
|
- (void)uploadNextChunkWithOffset:(int64_t)offset fetcherProperties:(NSDictionary *)props {
|
||||||
fetcherProperties:(NSDictionary *)props {
|
|
||||||
GTMSessionCheckNotSynchronized(self);
|
GTMSessionCheckNotSynchronized(self);
|
||||||
|
|
||||||
// Example chunk headers:
|
// Example chunk headers:
|
||||||
@ -1206,48 +1222,49 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// {bytes 0-1999999}
|
// {bytes 0-1999999}
|
||||||
|
|
||||||
// The chunk upload URL requires no authentication header.
|
// The chunk upload URL requires no authentication header.
|
||||||
GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props
|
GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props isQueryFetch:NO];
|
||||||
isQueryFetch:NO];
|
|
||||||
[self attachSendProgressBlockToChunkFetcher:chunkFetcher];
|
[self attachSendProgressBlockToChunkFetcher:chunkFetcher];
|
||||||
int64_t chunkSize = [self updateChunkFetcher:chunkFetcher
|
int64_t chunkSize = [self updateChunkFetcher:chunkFetcher forChunkAtOffset:offset];
|
||||||
forChunkAtOffset:offset];
|
|
||||||
BOOL isUploadingFileURL = (self.uploadFileURL != nil);
|
BOOL isUploadingFileURL = (self.uploadFileURL != nil);
|
||||||
int64_t fullUploadLength = [self fullUploadLength];
|
int64_t fullUploadLength = [self fullUploadLength];
|
||||||
|
|
||||||
// The chunk size may have changed, so determine again if we're uploading the full file.
|
// The chunk size may have changed, so determine again if we're uploading the full file.
|
||||||
BOOL isUploadingFullFile = (offset == 0 &&
|
BOOL isUploadingFullFile =
|
||||||
fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize &&
|
(offset == 0 && fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize &&
|
||||||
chunkSize >= fullUploadLength);
|
chunkSize >= fullUploadLength);
|
||||||
if (isUploadingFullFile && isUploadingFileURL) {
|
if (isUploadingFullFile && isUploadingFileURL) {
|
||||||
// The data is the full upload file URL.
|
// The data is the full upload file URL.
|
||||||
chunkFetcher.bodyFileURL = self.uploadFileURL;
|
chunkFetcher.bodyFileURL = self.uploadFileURL;
|
||||||
[self beginChunkFetcher:chunkFetcher
|
[self beginChunkFetcher:chunkFetcher offset:offset];
|
||||||
offset:offset];
|
|
||||||
} else {
|
} else {
|
||||||
// Make an NSData for the subset for this upload chunk.
|
// Make an NSData for the subset for this upload chunk.
|
||||||
self.subdataGenerating = YES;
|
self.subdataGenerating = YES;
|
||||||
[self generateChunkSubdataWithOffset:offset
|
[self generateChunkSubdataWithOffset:offset
|
||||||
length:chunkSize
|
length:chunkSize
|
||||||
response:^(NSData *chunkData, int64_t uploadFileLength, NSError *chunkError) {
|
response:^(NSData *chunkData, int64_t uploadFileLength,
|
||||||
|
NSError *chunkError) {
|
||||||
// The subdata methods may leave us on a background thread.
|
// The subdata methods may leave us on a background thread.
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
self.subdataGenerating = NO;
|
self.subdataGenerating = NO;
|
||||||
|
|
||||||
// dont allow the updating of fileLength for uploads not using a data provider as they
|
// dont allow the updating of fileLength for uploads not using a
|
||||||
// should know the file length before the upload starts.
|
// data provider as they should know the file length before the
|
||||||
|
// upload starts.
|
||||||
if (self->_uploadDataProvider != nil && uploadFileLength > 0) {
|
if (self->_uploadDataProvider != nil && uploadFileLength > 0) {
|
||||||
[self setUploadFileLength:uploadFileLength];
|
[self setUploadFileLength:uploadFileLength];
|
||||||
// Update the command and content-length headers if this is the last chunk to be sent.
|
// Update the command and content-length headers if this is
|
||||||
|
// the last chunk to be sent.
|
||||||
if (offset + chunkSize >= uploadFileLength) {
|
if (offset + chunkSize >= uploadFileLength) {
|
||||||
int64_t updatedChunkSize = [self updateChunkFetcher:chunkFetcher
|
int64_t updatedChunkSize =
|
||||||
|
[self updateChunkFetcher:chunkFetcher
|
||||||
forChunkAtOffset:offset];
|
forChunkAtOffset:offset];
|
||||||
if (updatedChunkSize == 0) {
|
if (updatedChunkSize == 0) {
|
||||||
// Calling beginChunkFetcher early when there is no more data to send allows us to
|
// Calling beginChunkFetcher early when there is no more
|
||||||
// properly handle nil chunkData below without having to account for the case where
|
// data to send allows us to properly handle nil chunkData
|
||||||
// we are just finalizing the file.
|
// below without having to account for the case where we
|
||||||
|
// are just finalizing the file.
|
||||||
chunkFetcher.bodyData = [[NSData alloc] init];
|
chunkFetcher.bodyData = [[NSData alloc] init];
|
||||||
[self beginChunkFetcher:chunkFetcher
|
[self beginChunkFetcher:chunkFetcher offset:offset];
|
||||||
offset:offset];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1256,7 +1273,9 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
if (chunkData == nil) {
|
if (chunkData == nil) {
|
||||||
NSError *responseError = chunkError;
|
NSError *responseError = chunkError;
|
||||||
if (!responseError) {
|
if (!responseError) {
|
||||||
responseError = [self uploadChunkUnavailableErrorWithDescription:@"chunkData is nil"];
|
responseError =
|
||||||
|
[self uploadChunkUnavailableErrorWithDescription:
|
||||||
|
@"chunkData is nil"];
|
||||||
}
|
}
|
||||||
[self invokeFinalCallbackWithData:nil
|
[self invokeFinalCallbackWithData:nil
|
||||||
error:responseError
|
error:responseError
|
||||||
@ -1268,8 +1287,10 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
if (isUploadingFileURL) {
|
if (isUploadingFileURL) {
|
||||||
// Make a temporary file with the data subset.
|
// Make a temporary file with the data subset.
|
||||||
NSString *tempName =
|
NSString *tempName =
|
||||||
[NSString stringWithFormat:@"GTMUpload_temp_%@", [[NSUUID UUID] UUIDString]];
|
[NSString stringWithFormat:@"GTMUpload_temp_%@",
|
||||||
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempName];
|
[[NSUUID UUID] UUIDString]];
|
||||||
|
NSString *tempPath = [NSTemporaryDirectory()
|
||||||
|
stringByAppendingPathComponent:tempName];
|
||||||
NSError *writeError;
|
NSError *writeError;
|
||||||
didWriteFile = [chunkData writeToFile:tempPath
|
didWriteFile = [chunkData writeToFile:tempPath
|
||||||
options:NSDataWritingAtomic
|
options:NSDataWritingAtomic
|
||||||
@ -1277,22 +1298,20 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
if (didWriteFile) {
|
if (didWriteFile) {
|
||||||
chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath];
|
chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath];
|
||||||
} else {
|
} else {
|
||||||
GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", writeError, tempPath);
|
GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@",
|
||||||
|
writeError, tempPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!didWriteFile) {
|
if (!didWriteFile) {
|
||||||
chunkFetcher.bodyData = [chunkData copy];
|
chunkFetcher.bodyData = [chunkData copy];
|
||||||
}
|
}
|
||||||
[self beginChunkFetcher:chunkFetcher
|
[self beginChunkFetcher:chunkFetcher offset:offset];
|
||||||
offset:offset];
|
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher
|
- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher offset:(int64_t)offset {
|
||||||
offset:(int64_t)offset {
|
|
||||||
|
|
||||||
// Track the current offset for progress reporting
|
// Track the current offset for progress reporting
|
||||||
self.currentOffset = offset;
|
self.currentOffset = offset;
|
||||||
|
|
||||||
@ -1310,8 +1329,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher {
|
- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher {
|
||||||
chunkFetcher.sendProgressBlock = ^(int64_t bytesSent, int64_t totalBytesSent,
|
chunkFetcher.sendProgressBlock =
|
||||||
int64_t totalBytesExpectedToSend) {
|
^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
|
||||||
// The total bytes expected include the initial body and the full chunked
|
// The total bytes expected include the initial body and the full chunked
|
||||||
// data, independent of how big this fetcher's chunk is.
|
// data, independent of how big this fetcher's chunk is.
|
||||||
int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent]
|
int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent]
|
||||||
@ -1404,9 +1423,9 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
if ([self isRetryEnabled]) {
|
if ([self isRetryEnabled]) {
|
||||||
// We interpose our own retry method both so we can change the request to ask the server to
|
// We interpose our own retry method both so we can change the request to ask the server to
|
||||||
// tell us where to resume the chunk.
|
// tell us where to resume the chunk.
|
||||||
chunkFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *chunkError,
|
chunkFetcher.retryBlock =
|
||||||
GTMSessionFetcherRetryResponse response) {
|
^(BOOL suggestedWillRetry, NSError *chunkError, GTMSessionFetcherRetryResponse response) {
|
||||||
void (^finish)(BOOL) = ^(BOOL shouldRetry){
|
void (^finish)(BOOL) = ^(BOOL shouldRetry) {
|
||||||
// We'll retry by sending an offset query.
|
// We'll retry by sending an offset query.
|
||||||
if (shouldRetry) {
|
if (shouldRetry) {
|
||||||
self.shouldInitiateOffsetQuery = !isQueryFetch;
|
self.shouldInitiateOffsetQuery = !isQueryFetch;
|
||||||
@ -1440,9 +1459,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
NSDictionary *responseHeaders = [chunkFetcher responseHeaders];
|
NSDictionary *responseHeaders = [chunkFetcher responseHeaders];
|
||||||
GTMSessionUploadFetcherStatus uploadStatus =
|
GTMSessionUploadFetcherStatus uploadStatus =
|
||||||
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
[[self class] uploadStatusFromResponseHeaders:responseHeaders];
|
||||||
GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown
|
GTMSESSION_ASSERT_DEBUG(
|
||||||
|| error != nil
|
uploadStatus != kStatusUnknown || error != nil || self.wasCreatedFromBackgroundSession,
|
||||||
|| self.wasCreatedFromBackgroundSession,
|
|
||||||
@"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@",
|
@"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@",
|
||||||
responseHeaders, self);
|
responseHeaders, self);
|
||||||
BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled);
|
BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled);
|
||||||
@ -1454,7 +1472,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
BOOL isQueryFetch = [uploadCommand isEqual:@"query"];
|
BOOL isQueryFetch = [uploadCommand isEqual:@"query"];
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Maybe here we can check to see if the request had x goog content length set. (the file length one).
|
// Maybe here we can check to see if the request had x goog content length set. (the file length
|
||||||
|
// one).
|
||||||
NSString *previousContentLengthValue =
|
NSString *previousContentLengthValue =
|
||||||
[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"];
|
[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"];
|
||||||
// The Content-Length header may not be present if the chunk fetcher was recreated from
|
// The Content-Length header may not be present if the chunk fetcher was recreated from
|
||||||
@ -1470,13 +1489,9 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status
|
// Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status
|
||||||
// 404 per spec, nor if the upload size appears to have been zero (since the server will just
|
// 404 per spec, nor if the upload size appears to have been zero (since the server will just
|
||||||
// keep asking us to retry.)
|
// keep asking us to retry.)
|
||||||
if (self.shouldInitiateOffsetQuery ||
|
if (self.shouldInitiateOffsetQuery || (needsQuery && !isQueryFetch) ||
|
||||||
(needsQuery && !isQueryFetch) ||
|
([error.domain isEqual:kGTMSessionFetcherStatusDomain] && status >= 400 && status <= 499 &&
|
||||||
([error.domain isEqual:kGTMSessionFetcherStatusDomain] &&
|
status != 404 && uploadStatus == kStatusActive && previousContentLength > 0)) {
|
||||||
status >= 400 && status <= 499 &&
|
|
||||||
status != 404 &&
|
|
||||||
uploadStatus == kStatusActive &&
|
|
||||||
previousContentLength > 0)) {
|
|
||||||
self.shouldInitiateOffsetQuery = NO;
|
self.shouldInitiateOffsetQuery = NO;
|
||||||
[self destroyChunkFetcher];
|
[self destroyChunkFetcher];
|
||||||
hasDestroyedOldChunkFetcher = YES;
|
hasDestroyedOldChunkFetcher = YES;
|
||||||
@ -1484,9 +1499,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
} else {
|
} else {
|
||||||
// Some unexpected status has occurred; handle it as we would a regular
|
// Some unexpected status has occurred; handle it as we would a regular
|
||||||
// object fetcher failure.
|
// object fetcher failure.
|
||||||
[self invokeFinalCallbackWithData:data
|
[self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:NO];
|
||||||
error:error
|
|
||||||
shouldInvalidateLocation:NO];
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The chunk has uploaded successfully.
|
// The chunk has uploaded successfully.
|
||||||
@ -1496,25 +1509,23 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
// the "final" upload status.
|
// the "final" upload status.
|
||||||
BOOL hasUploadAllData = (newOffset == [self fullUploadLength]);
|
BOOL hasUploadAllData = (newOffset == [self fullUploadLength]);
|
||||||
BOOL isFinalStatus = (uploadStatus == kStatusFinal);
|
BOOL isFinalStatus = (uploadStatus == kStatusFinal);
|
||||||
#pragma unused(hasUploadAllData,isFinalStatus)
|
#pragma unused(hasUploadAllData, isFinalStatus)
|
||||||
GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize,
|
GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize,
|
||||||
@"uploadStatus:%@ newOffset:%lld (%lld + %lld) fullUploadLength:%lld"
|
@"uploadStatus:%@ newOffset:%lld (%lld + %lld) fullUploadLength:%lld"
|
||||||
@" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@",
|
@" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@",
|
||||||
[responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus],
|
[responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus],
|
||||||
newOffset, self.currentOffset, previousContentLength,
|
newOffset, self.currentOffset, previousContentLength,
|
||||||
[self fullUploadLength],
|
[self fullUploadLength], chunkFetcher,
|
||||||
chunkFetcher, chunkFetcher.request.allHTTPHeaderFields,
|
chunkFetcher.request.allHTTPHeaderFields, responseHeaders);
|
||||||
responseHeaders);
|
|
||||||
#endif
|
#endif
|
||||||
if (isUploadStatusStopped ||
|
if (isUploadStatusStopped || (!_uploadData && _uploadFileLength == 0) ||
|
||||||
(!_uploadData && _uploadFileLength == 0) ||
|
|
||||||
(_currentOffset > _uploadFileLength && _uploadFileLength > 0)) {
|
(_currentOffset > _uploadFileLength && _uploadFileLength > 0)) {
|
||||||
// This was the last chunk.
|
// This was the last chunk.
|
||||||
if (error == nil && uploadStatus == kStatusCancelled) {
|
if (error == nil && uploadStatus == kStatusCancelled) {
|
||||||
// Report cancelled status as an error.
|
// Report cancelled status as an error.
|
||||||
NSDictionary *userInfo = nil;
|
NSDictionary *userInfo = nil;
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
userInfo = @{ kGTMSessionFetcherStatusDataKey : data };
|
userInfo = @{kGTMSessionFetcherStatusDataKey : data};
|
||||||
}
|
}
|
||||||
data = nil;
|
data = nil;
|
||||||
error = [self prematureFailureErrorWithUserInfo:userInfo];
|
error = [self prematureFailureErrorWithUserInfo:userInfo];
|
||||||
@ -1527,9 +1538,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we're done
|
// we're done
|
||||||
[self invokeFinalCallbackWithData:data
|
[self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES];
|
||||||
error:error
|
|
||||||
shouldInvalidateLocation:YES];
|
|
||||||
} else {
|
} else {
|
||||||
// Start the next chunk.
|
// Start the next chunk.
|
||||||
self.currentOffset = newOffset;
|
self.currentOffset = newOffset;
|
||||||
@ -1543,8 +1552,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
[self destroyChunkFetcher];
|
[self destroyChunkFetcher];
|
||||||
hasDestroyedOldChunkFetcher = YES;
|
hasDestroyedOldChunkFetcher = YES;
|
||||||
|
|
||||||
[self uploadNextChunkWithOffset:newOffset
|
[self uploadNextChunkWithOffset:newOffset fetcherProperties:props];
|
||||||
fetcherProperties:props];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasDestroyedOldChunkFetcher) {
|
if (!hasDestroyedOldChunkFetcher) {
|
||||||
@ -1566,8 +1574,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL];
|
BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL];
|
||||||
if (wasTemporaryUploadFile) {
|
if (wasTemporaryUploadFile) {
|
||||||
NSError *error;
|
NSError *error;
|
||||||
[[NSFileManager defaultManager] removeItemAtURL:chunkFileURL
|
[[NSFileManager defaultManager] removeItemAtURL:chunkFileURL error:&error];
|
||||||
error:&error];
|
|
||||||
if (error) {
|
if (error) {
|
||||||
GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL);
|
GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL);
|
||||||
}
|
}
|
||||||
@ -1577,7 +1584,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
// To avoid retain cycles, remove all properties except the parent identifier.
|
// To avoid retain cycles, remove all properties except the parent identifier.
|
||||||
_chunkFetcher.properties =
|
_chunkFetcher.properties =
|
||||||
@{ kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self] };
|
@{kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self]};
|
||||||
|
|
||||||
_chunkFetcher.retryBlock = nil;
|
_chunkFetcher.retryBlock = nil;
|
||||||
_chunkFetcher.sendProgressBlock = nil;
|
_chunkFetcher.sendProgressBlock = nil;
|
||||||
@ -1595,13 +1602,20 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
totalBytesExpectedToSend:(int64_t)totalBytesExpected {
|
totalBytesExpectedToSend:(int64_t)totalBytesExpected {
|
||||||
GTMSessionCheckNotSynchronized(self);
|
GTMSessionCheckNotSynchronized(self);
|
||||||
|
|
||||||
|
// 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"
|
||||||
// Ensure the chunk fetcher survives the callback in case the user pauses the upload process.
|
// Ensure the chunk fetcher survives the callback in case the user pauses the upload process.
|
||||||
__block GTMSessionFetcher *holdFetcher = self.chunkFetcher;
|
__block GTMSessionFetcher *holdFetcher = self.chunkFetcher;
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
[self invokeOnCallbackQueue:self.delegateCallbackQueue
|
[self invokeOnCallbackQueue:self.delegateCallbackQueue
|
||||||
afterUserStopped:NO
|
afterUserStopped:NO
|
||||||
block:^{
|
block:^{
|
||||||
GTMSessionFetcherSendProgressBlock sendProgressBlock = self.sendProgressBlock;
|
GTMSessionFetcherSendProgressBlock sendProgressBlock =
|
||||||
|
self.sendProgressBlock;
|
||||||
if (sendProgressBlock) {
|
if (sendProgressBlock) {
|
||||||
sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected);
|
sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected);
|
||||||
}
|
}
|
||||||
@ -1671,9 +1685,10 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
[self invokeOnCallbackQueue:self.callbackQueue
|
[self invokeOnCallbackQueue:self.callbackQueue
|
||||||
afterUserStopped:YES
|
afterUserStopped:YES
|
||||||
block:^{
|
block:^{
|
||||||
// Repeated calls to stopFetching may cause this path to be reached despite having sent a real
|
// Repeated calls to stopFetching may cause this path to be reached
|
||||||
// cancel request, check here to ensure that the cancellation handler invocation which fires
|
// despite having sent a real cancel request, check here to ensure that
|
||||||
// will definitely be for the real request sent previously.
|
// the cancellation handler invocation which fires will definitely be
|
||||||
|
// for the real request sent previously.
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
if (self->_isCancelInFlight) {
|
if (self->_isCancelInFlight) {
|
||||||
return;
|
return;
|
||||||
@ -1701,8 +1716,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
- (int64_t)updateChunkFetcher:(GTMSessionFetcher *)chunkFetcher
|
- (int64_t)updateChunkFetcher:(GTMSessionFetcher *)chunkFetcher forChunkAtOffset:(int64_t)offset {
|
||||||
forChunkAtOffset:(int64_t)offset {
|
|
||||||
BOOL isUploadingFileURL = (self.uploadFileURL != nil);
|
BOOL isUploadingFileURL = (self.uploadFileURL != nil);
|
||||||
|
|
||||||
// Upload another chunk, meeting server-required granularity.
|
// Upload another chunk, meeting server-required granularity.
|
||||||
@ -1770,13 +1784,14 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
|
|
||||||
// Append the range of bytes in this chunk to the fetcher comment.
|
// Append the range of bytes in this chunk to the fetcher comment.
|
||||||
NSString *baseComment = self.comment;
|
NSString *baseComment = self.comment;
|
||||||
[chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)",
|
[chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", baseComment ? baseComment : @"upload",
|
||||||
baseComment ? baseComment : @"upload", offset, MAX(0, offset + thisChunkSize - 1)];
|
offset, MAX(0, offset + thisChunkSize - 1)];
|
||||||
|
|
||||||
return thisChunkSize;
|
return thisChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public properties.
|
// Public properties.
|
||||||
|
// clang-format off
|
||||||
@synthesize currentOffset = _currentOffset,
|
@synthesize currentOffset = _currentOffset,
|
||||||
allowsCellularAccess = _allowsCellularAccess,
|
allowsCellularAccess = _allowsCellularAccess,
|
||||||
delegateCompletionHandler = _delegateCompletionHandler,
|
delegateCompletionHandler = _delegateCompletionHandler,
|
||||||
@ -1785,6 +1800,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
subdataGenerating = _subdataGenerating,
|
subdataGenerating = _subdataGenerating,
|
||||||
shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery,
|
shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery,
|
||||||
uploadGranularity = _uploadGranularity;
|
uploadGranularity = _uploadGranularity;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
// Internal properties.
|
// Internal properties.
|
||||||
@dynamic fetcherInFlight;
|
@dynamic fetcherInFlight;
|
||||||
@ -1873,7 +1889,6 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)setStatusCode:(NSInteger)val {
|
- (void)setStatusCode:(NSInteger)val {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
GTMSessionMonitorSynchronized(self);
|
GTMSessionMonitorSynchronized(self);
|
||||||
@ -1945,6 +1960,8 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
return [super isFetching];
|
return [super isFetching];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||||
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds {
|
- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds {
|
||||||
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds];
|
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds];
|
||||||
|
|
||||||
@ -1970,6 +1987,7 @@ NSString *const kGTMSessionFetcherUploadLocationObtainedNotification =
|
|||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
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
|
# 2018-11-26 -- v4.4.0
|
||||||
- Removes the dependency on GTM OAuth 2.
|
- Removes the dependency on GTM OAuth 2.
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -13,60 +13,53 @@
|
|||||||
@protocol GTMFetcherAuthorizationProtocol;
|
@protocol GTMFetcherAuthorizationProtocol;
|
||||||
@class GIDAuthentication;
|
@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);
|
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);
|
typedef void (^GIDAccessTokenHandler)(NSString *accessToken, NSError *error);
|
||||||
|
|
||||||
// This class represents the OAuth 2.0 entities needed for sign-in.
|
/// This class represents the OAuth 2.0 entities needed for sign-in.
|
||||||
@interface GIDAuthentication : NSObject <NSCoding>
|
@interface GIDAuthentication : NSObject <NSSecureCoding>
|
||||||
|
|
||||||
// The client ID associated with the authentication.
|
/// The client ID associated with the authentication.
|
||||||
@property(nonatomic, readonly) NSString *clientID;
|
@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;
|
@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;
|
@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;
|
@property(nonatomic, readonly) NSString *refreshToken;
|
||||||
|
|
||||||
// An OpenID Connect ID token that identifies the user. Send this token to your server to
|
/// 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
|
/// authenticate the user there. For more information on this topic, see
|
||||||
// https://developers.google.com/identity/sign-in/ios/backend-auth
|
/// https://developers.google.com/identity/sign-in/ios/backend-auth
|
||||||
@property(nonatomic, readonly) NSString *idToken;
|
@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;
|
@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;
|
- (id<GTMFetcherAuthorizationProtocol>)fetcherAuthorizer;
|
||||||
|
|
||||||
// Get a valid access token and a valid ID token, refreshing them first if they have expired or are
|
/// Get a valid access token and a valid ID token, refreshing them first if they have expired or are
|
||||||
// about to expire.
|
/// 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;
|
- (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;
|
- (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
|
@end
|
||||||
|
|||||||
@ -13,31 +13,27 @@
|
|||||||
@class GIDAuthentication;
|
@class GIDAuthentication;
|
||||||
@class GIDProfileData;
|
@class GIDProfileData;
|
||||||
|
|
||||||
// This class represents a user account.
|
/// This class represents a user account.
|
||||||
@interface GIDGoogleUser : NSObject <NSCoding>
|
@interface GIDGoogleUser : NSObject <NSSecureCoding>
|
||||||
|
|
||||||
// The Google user ID.
|
/// The Google user ID.
|
||||||
@property(nonatomic, readonly) NSString *userID;
|
@property(nonatomic, readonly) NSString *userID;
|
||||||
|
|
||||||
// Representation of the Basic profile data. It is only available if |shouldFetchBasicProfile|
|
/// Representation of the Basic profile data. It is only available if
|
||||||
// is set and either |signIn| or |signInSilently| has been completed successfully.
|
/// `GIDSignIn.shouldFetchBasicProfile` is set and either `-[GIDSignIn signIn]` or
|
||||||
|
/// `-[GIDSignIn restorePreviousSignIn]` has been completed successfully.
|
||||||
@property(nonatomic, readonly) GIDProfileData *profile;
|
@property(nonatomic, readonly) GIDProfileData *profile;
|
||||||
|
|
||||||
// The authentication object for the user.
|
/// The authentication object for the user.
|
||||||
@property(nonatomic, readonly) GIDAuthentication *authentication;
|
@property(nonatomic, readonly) GIDAuthentication *authentication;
|
||||||
|
|
||||||
// The API scopes requested by the app in an array of |NSString|s. Deprecated.
|
/// The API scopes granted to the app in an array of `NSString`.
|
||||||
// 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.
|
|
||||||
@property(nonatomic, readonly) NSArray *grantedScopes;
|
@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;
|
@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;
|
@property(nonatomic, readonly) NSString *serverAuthCode;
|
||||||
|
|
||||||
@end
|
@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