Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial tvOS support #959

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion A0Auth0.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.homepage = package['repository']['baseUrl']
s.license = package['license']
s.authors = package['author']
s.platforms = { :ios => '13.0' }
s.platforms = { :ios => '13.0', :tvos => '14.0' }
s.source = { :git => 'https://github.com/auth0/react-native-auth0.git', :tag => "v#{s.version}" }

s.source_files = 'ios/**/*.{h,m,mm,swift}'
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,25 @@ The following shows platform minimums for running projects with this SDK:
| Platform | Minimum version |
| -------- | :-------------: |
| iOS | 13.0 |
| tvOS | 14.0 |
| Android | 28 |

**iOS**

Our SDK requires a minimum iOS deployment target of 13.0. In your project's ios/Podfile, ensure your platform target is set to 13.0.

```
platform :ios, '13.0'
```

**tvOS**

Our SDK requires a minimum tvOS deployment target of 14.0. In your project's ios/Podfile, ensure your platform target is set to 14.0.

```
platform :tvos, '14.0'
```

### Installation

First install the native library module:
Expand Down
155 changes: 88 additions & 67 deletions ios/NativeBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public class NativeBridge: NSObject {
self.domain = domain
self.credentialsManager = CredentialsManager(authentication: auth0)
super.init()

#if os(iOS)
if let localAuthenticationOptions = localAuthenticationOptions {
if let title = localAuthenticationOptions["title"] as? String {
var evaluationPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
Expand All @@ -51,82 +53,95 @@ public class NativeBridge: NSObject {
return
}
}
#endif

resolve(true)
}

@objc public func webAuth(state: String?, redirectUri: String, nonce: String?, audience: String?, scope: String?, connection: String?, maxAge: Int, organization: String?, invitationUrl: String?, leeway: Int, ephemeralSession: Bool, safariViewControllerPresentationStyle: Int, additionalParameters: [String: String], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
let builder = Auth0.webAuth(clientId: self.clientId, domain: self.domain)
if let value = URL(string: redirectUri) {
let _ = builder.redirectURL(value)
}
if let value = state {
let _ = builder.state(value)
}
if let value = nonce {
let _ = builder.nonce(value)
}
if let value = audience {
let _ = builder.audience(value)
}
if let value = scope {
let _ = builder.scope(value)
}
if let value = connection {
let _ = builder.connection(value)
}
if(maxAge != 0) {
let _ = builder.maxAge(maxAge)
}
if let value = organization {
let _ = builder.organization(value)
}
if let value = invitationUrl, let invitationURL = URL(string: value) {
let _ = builder.invitationURL(invitationURL)
}
if(leeway != 0) {
let _ = builder.leeway(leeway)
}
if(ephemeralSession) {
let _ = builder.useEphemeralSession()
}
//Since we cannot have a null value here, the JS layer sends 99 if we have to ignore setting this value
if let presentationStyle = UIModalPresentationStyle(rawValue: safariViewControllerPresentationStyle), safariViewControllerPresentationStyle != 99 {
let _ = builder.provider(WebAuthentication.safariProvider(style: presentationStyle))
}
let _ = builder
.parameters(additionalParameters)
builder.start { result in
switch result {
case .success(let credentials):
resolve(credentials.asDictionary())
case .failure(let error):
reject(error.reactNativeErrorCode(), error.errorDescription, error)
#if os(tvOS)
reject("UNSUPPORTED_OPERATION", "webAuth is unsupported on tvOS", nil)
#else
let builder = Auth0.webAuth(clientId: self.clientId, domain: self.domain)
if let value = URL(string: redirectUri) {
let _ = builder.redirectURL(value)
}
}

}

@objc public func webAuthLogout(federated: Bool, redirectUri: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
let builder = Auth0.webAuth(clientId: self.clientId, domain: self.domain)
if let value = URL(string: redirectUri) {
let _ = builder.redirectURL(value)
}
builder.clearSession(federated: federated) { result in
if let value = state {
let _ = builder.state(value)
}
if let value = nonce {
let _ = builder.nonce(value)
}
if let value = audience {
let _ = builder.audience(value)
}
if let value = scope {
let _ = builder.scope(value)
}
if let value = connection {
let _ = builder.connection(value)
}
if(maxAge != 0) {
let _ = builder.maxAge(maxAge)
}
if let value = organization {
let _ = builder.organization(value)
}
if let value = invitationUrl, let invitationURL = URL(string: value) {
let _ = builder.invitationURL(invitationURL)
}
if(leeway != 0) {
let _ = builder.leeway(leeway)
}
if(ephemeralSession) {
let _ = builder.useEphemeralSession()
}
//Since we cannot have a null value here, the JS layer sends 99 if we have to ignore setting this value
if let presentationStyle = UIModalPresentationStyle(rawValue: safariViewControllerPresentationStyle), safariViewControllerPresentationStyle != 99 {
let _ = builder.provider(WebAuthentication.safariProvider(style: presentationStyle))
}
let _ = builder
.parameters(additionalParameters)
builder.start { result in
switch result {
case .success:
resolve(true)
case .success(let credentials):
resolve(credentials.asDictionary())
case .failure(let error):
reject(error.reactNativeErrorCode(), error.errorDescription, error)
}
}
#endif
}

@objc public func webAuthLogout(federated: Bool, redirectUri: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
#if os(tvOS)
reject("UNSUPPORTED_OPERATION", "webAuthLogout is unsupported on tvOS", nil)
#else
let builder = Auth0.webAuth(clientId: self.clientId, domain: self.domain)
if let value = URL(string: redirectUri) {
let _ = builder.redirectURL(value)
}
builder.clearSession(federated: federated) { result in
switch result {
case .success:
resolve(true)
case .failure(let error):
reject(error.reactNativeErrorCode(), error.errorDescription, error)
}
}
#endif
}

@objc public func resumeWebAuth(url: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
if let value = URL(string: url), WebAuthentication.resume(with: value) {
resolve(true)
} else {
reject("ERROR_PARSING_URL", "The callback url \(url) is invalid", nil)
}
#if os(tvOS)
reject("UNSUPPORTED_OPERATION", "resumeWebAuth is unsupported on tvOS", nil)
#else
if let value = URL(string: url), WebAuthentication.resume(with: value) {
resolve(true)
} else {
reject("ERROR_PARSING_URL", "The callback url \(url) is invalid", nil)
}
#endif
}

@objc public func saveCredentials(credentialsDict: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
Expand Down Expand Up @@ -192,9 +207,11 @@ public class NativeBridge: NSObject {
}

@objc public func enableLocalAuthentication(title: String?, cancelTitle: String?, fallbackTitle: String?, evaluationPolicy: Int) {
let titleValue = title ?? "Please authenticate to continue"
let policyValue = self.convert(policyInt: evaluationPolicy)
self.credentialsManager.enableBiometrics(withTitle: titleValue, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle, evaluationPolicy: policyValue)
#if os(iOS)
let titleValue = title ?? "Please authenticate to continue"
let policyValue = self.convert(policyInt: evaluationPolicy)
self.credentialsManager.enableBiometrics(withTitle: titleValue, cancelTitle: cancelTitle, fallbackTitle: fallbackTitle, evaluationPolicy: policyValue)
#endif
}

@objc public func getClientId() -> String {
Expand All @@ -205,12 +222,14 @@ public class NativeBridge: NSObject {
return domain
}

#if os(iOS)
func convert(policyInt: Int) -> LAPolicy {
if (policyInt == 2) {
return LAPolicy.deviceOwnerAuthentication
}
return LAPolicy.deviceOwnerAuthenticationWithBiometrics
}
#endif
}


Expand All @@ -227,6 +246,7 @@ extension Credentials {
}
}

#if os(iOS)
extension WebAuthError {
func reactNativeErrorCode() -> String {
var code: String
Expand All @@ -247,6 +267,7 @@ extension WebAuthError {
return code
}
}
#endif

extension CredentialsManagerError {
func reactNativeErrorCode() -> String {
Expand All @@ -265,7 +286,7 @@ extension CredentialsManagerError {
code = cause.code
} else {
code = "REVOKE_FAILED"
}
}
case .largeMinTTL: code = "LARGE_MIN_TTL"
default: code = "UNKNOWN"
}
Expand Down