react-native-oauth-essentials 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/OauthEssentials.podspec +22 -0
- package/README.md +30 -0
- package/android/build.gradle +74 -0
- package/android/src/main/AndroidManifest.xml +22 -0
- package/android/src/main/java/com/oauthessentials/CredentialError.kt +7 -0
- package/android/src/main/java/com/oauthessentials/CredentialFactory.kt +114 -0
- package/android/src/main/java/com/oauthessentials/CustomTabsActivity.kt +133 -0
- package/android/src/main/java/com/oauthessentials/OauthEssentialsModule.kt +603 -0
- package/android/src/main/java/com/oauthessentials/OauthEssentialsPackage.kt +33 -0
- package/android/src/main/java/com/oauthessentials/RCTPromiseSettler.kt +60 -0
- package/ios/AppleIdRetriever.swift +61 -0
- package/ios/CredentialError.swift +6 -0
- package/ios/CredentialFactory.swift +133 -0
- package/ios/CredentialsType.swift +7 -0
- package/ios/GoogleIdRetriever.swift +83 -0
- package/ios/HybridRetriever.swift +64 -0
- package/ios/OauthEssentials.h +8 -0
- package/ios/OauthEssentials.mm +104 -0
- package/ios/OauthEssentialsModule.swift +210 -0
- package/ios/PasskeyRetriever.swift +226 -0
- package/ios/PasswordRetriever.swift +72 -0
- package/ios/RCTPromiseSettler.swift +28 -0
- package/lib/module/NativeOauthEssentials.js +5 -0
- package/lib/module/NativeOauthEssentials.js.map +1 -0
- package/lib/module/index.js +148 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +23 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeOauthEssentials.d.ts +60 -0
- package/lib/typescript/src/NativeOauthEssentials.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +78 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +71 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +156 -0
- package/src/NativeOauthEssentials.ts +75 -0
- package/src/index.tsx +199 -0
- package/src/types.ts +79 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import AuthenticationServices
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
public class AppleIdRetriever: RCTPromiseSettler,
|
|
5
|
+
ASAuthorizationControllerDelegate,
|
|
6
|
+
ASAuthorizationControllerPresentationContextProviding {
|
|
7
|
+
|
|
8
|
+
override init(
|
|
9
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
10
|
+
reject: @escaping RCTPromiseRejectBlock,
|
|
11
|
+
emitEvent: ((String, NSDictionary) -> Void)?
|
|
12
|
+
) {
|
|
13
|
+
super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
|
|
14
|
+
|
|
15
|
+
let controller = ASAuthorizationController(authorizationRequests: [
|
|
16
|
+
ASAuthorizationAppleIDProvider().createRequest(),
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
controller.delegate = self
|
|
20
|
+
controller.presentationContextProvider = self
|
|
21
|
+
|
|
22
|
+
if #available(iOS 16.0, *) {
|
|
23
|
+
controller.performRequests(options: .preferImmediatelyAvailableCredentials)
|
|
24
|
+
} else {
|
|
25
|
+
controller.performRequests()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
|
30
|
+
return UIWindow()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public func authorizationController(
|
|
34
|
+
controller: ASAuthorizationController,
|
|
35
|
+
didCompleteWithAuthorization authorization: ASAuthorization
|
|
36
|
+
) {
|
|
37
|
+
if let appleIdCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
|
38
|
+
let result = CredentialFactory.fromAppleId(appleIdCredential: appleIdCredential)
|
|
39
|
+
self.resolve?(result)
|
|
40
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
41
|
+
cleanup()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
|
46
|
+
let nsError = error as NSError
|
|
47
|
+
if nsError.domain == ASAuthorizationError.errorDomain,
|
|
48
|
+
nsError.code == ASAuthorizationError.canceled.rawValue {
|
|
49
|
+
|
|
50
|
+
let result = CredentialFactory.fromCancelled()
|
|
51
|
+
self.resolve?(result)
|
|
52
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
53
|
+
} else {
|
|
54
|
+
self.emitEvent?("onCredentialFailure", [
|
|
55
|
+
"code": CredentialError.invalidResult.rawValue,
|
|
56
|
+
"message": error.localizedDescription
|
|
57
|
+
])
|
|
58
|
+
}
|
|
59
|
+
cleanup()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import AuthenticationServices
|
|
2
|
+
import GoogleSignIn
|
|
3
|
+
|
|
4
|
+
class CredentialFactory {
|
|
5
|
+
|
|
6
|
+
public static func fromCancelled() -> [String: Any] {
|
|
7
|
+
return [
|
|
8
|
+
"type": CredentialsType.cancelled.rawValue,
|
|
9
|
+
"data": NSNull()
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static func fromAppleId(appleIdCredential: ASAuthorizationAppleIDCredential) -> [String: Any] {
|
|
14
|
+
let idToken: Any =
|
|
15
|
+
appleIdCredential.identityToken
|
|
16
|
+
.flatMap { String(data: $0, encoding: .utf8) } ?? NSNull()
|
|
17
|
+
|
|
18
|
+
let authorizationCode: Any =
|
|
19
|
+
appleIdCredential.authorizationCode
|
|
20
|
+
.flatMap { String(data: $0, encoding: .utf8) } ?? NSNull()
|
|
21
|
+
|
|
22
|
+
let fullName =
|
|
23
|
+
appleIdCredential.fullName
|
|
24
|
+
.flatMap { PersonNameComponentsFormatter().string(from: $0) } ?? ""
|
|
25
|
+
|
|
26
|
+
let data: [String: Any] = [
|
|
27
|
+
"idToken": idToken,
|
|
28
|
+
"authorizationCode": authorizationCode,
|
|
29
|
+
"user": appleIdCredential.user,
|
|
30
|
+
"email": appleIdCredential.email ?? "",
|
|
31
|
+
"fullName": fullName,
|
|
32
|
+
"likelyReal": appleIdCredential.realUserStatus == .likelyReal
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
let result: [String: Any] = [
|
|
36
|
+
"type": CredentialsType.appleId.rawValue,
|
|
37
|
+
"data": data
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static func fromPassword(credential: ASPasswordCredential) -> [String: Any] {
|
|
44
|
+
let data: [String: Any] = [
|
|
45
|
+
"username": credential.user, "password": credential.password
|
|
46
|
+
]
|
|
47
|
+
let result: [String: Any] = [
|
|
48
|
+
"type": CredentialsType.password.rawValue,
|
|
49
|
+
"data": data
|
|
50
|
+
]
|
|
51
|
+
return result
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@available(iOS 16.0, *)
|
|
55
|
+
public static func fromPasskeyRegistration(credential: ASAuthorizationPlatformPublicKeyCredentialRegistration) -> [String: Any] {
|
|
56
|
+
let responseJson: [String: Any] = [
|
|
57
|
+
"id": base64URLEncode(credential.credentialID),
|
|
58
|
+
"rawId": base64URLEncode(credential.credentialID),
|
|
59
|
+
"type": "public-key",
|
|
60
|
+
"response": [
|
|
61
|
+
"clientDataJSON": base64URLEncode(credential.rawClientDataJSON),
|
|
62
|
+
"attestationObject": base64URLEncode(credential.rawAttestationObject ?? Data())
|
|
63
|
+
]
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: responseJson),
|
|
67
|
+
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
68
|
+
return [
|
|
69
|
+
"type": CredentialsType.passkey.rawValue,
|
|
70
|
+
"data": "{}"
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return [
|
|
75
|
+
"type": CredentialsType.passkey.rawValue,
|
|
76
|
+
"data": jsonString
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@available(iOS 16.0, *)
|
|
81
|
+
public static func fromPasskeyAssertion(credential: ASAuthorizationPlatformPublicKeyCredentialAssertion) -> [String: Any] {
|
|
82
|
+
let responseJson: [String: Any] = [
|
|
83
|
+
"id": base64URLEncode(credential.credentialID),
|
|
84
|
+
"rawId": base64URLEncode(credential.credentialID),
|
|
85
|
+
"type": "public-key",
|
|
86
|
+
"response": [
|
|
87
|
+
"clientDataJSON": base64URLEncode(credential.rawClientDataJSON),
|
|
88
|
+
"authenticatorData": base64URLEncode(credential.rawAuthenticatorData),
|
|
89
|
+
"signature": base64URLEncode(credential.signature),
|
|
90
|
+
"userHandle": base64URLEncode(credential.userID)
|
|
91
|
+
]
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: responseJson),
|
|
95
|
+
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
96
|
+
return [
|
|
97
|
+
"type": CredentialsType.passkey.rawValue,
|
|
98
|
+
"data": "{}"
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return [
|
|
103
|
+
"type": CredentialsType.passkey.rawValue,
|
|
104
|
+
"data": jsonString
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private static func base64URLEncode(_ data: Data) -> String {
|
|
109
|
+
return data.base64EncodedString()
|
|
110
|
+
.replacingOccurrences(of: "+", with: "-")
|
|
111
|
+
.replacingOccurrences(of: "/", with: "_")
|
|
112
|
+
.replacingOccurrences(of: "=", with: "")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public static func fromGoogleId(user: GIDGoogleUser) -> [String: Any] {
|
|
116
|
+
let profile = user.profile
|
|
117
|
+
let data: [String: Any] = [
|
|
118
|
+
"idToken": user.idToken?.tokenString ?? "",
|
|
119
|
+
"id": user.userID ?? "",
|
|
120
|
+
"displayName": profile?.name ?? "",
|
|
121
|
+
"givenName": profile?.givenName ?? "",
|
|
122
|
+
"familyName": profile?.familyName ?? "",
|
|
123
|
+
"profilePictureUri": profile?.imageURL(withDimension: 200)?.absoluteString ?? "",
|
|
124
|
+
"email": profile?.email ?? ""
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
let result: [String: Any] = [
|
|
128
|
+
"type": CredentialsType.googleId.rawValue,
|
|
129
|
+
"data": data
|
|
130
|
+
]
|
|
131
|
+
return result
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import GoogleSignIn
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
public class GoogleIdRetriever: RCTPromiseSettler {
|
|
5
|
+
|
|
6
|
+
init(
|
|
7
|
+
clientId: String,
|
|
8
|
+
options: NSDictionary,
|
|
9
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
10
|
+
reject: @escaping RCTPromiseRejectBlock,
|
|
11
|
+
emitEvent: ((String, NSDictionary) -> Void)?
|
|
12
|
+
) {
|
|
13
|
+
super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
|
|
14
|
+
performGoogleSignIn(clientId:clientId, options: options)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private func performGoogleSignIn(clientId: String, options: NSDictionary) {
|
|
18
|
+
var rootVC: UIViewController?
|
|
19
|
+
DispatchQueue.main.sync {
|
|
20
|
+
if #available(iOS 13.0, *) {
|
|
21
|
+
rootVC = UIApplication.shared.connectedScenes
|
|
22
|
+
.compactMap { $0 as? UIWindowScene }
|
|
23
|
+
.flatMap { $0.windows }
|
|
24
|
+
.first { $0.isKeyWindow }?
|
|
25
|
+
.rootViewController
|
|
26
|
+
} else {
|
|
27
|
+
rootVC = UIApplication.shared.keyWindow?.rootViewController
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
guard let rootVC = rootVC else {
|
|
32
|
+
self.reject?(
|
|
33
|
+
CredentialError.noSignInAvailable.rawValue,
|
|
34
|
+
"No root view controller available",
|
|
35
|
+
nil
|
|
36
|
+
)
|
|
37
|
+
self.emitEvent?("onCredentialFailure", [
|
|
38
|
+
"code": CredentialError.noSignInAvailable.rawValue,
|
|
39
|
+
"message": "No root view controller available"
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
self.cleanup()
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
GIDSignIn.sharedInstance.configuration = GIDConfiguration(clientID: clientId)
|
|
47
|
+
GIDSignIn.sharedInstance.signIn(withPresenting: rootVC) { result, error in
|
|
48
|
+
|
|
49
|
+
if let error = error {
|
|
50
|
+
let nsError = error as NSError
|
|
51
|
+
if nsError.code == GIDSignInError.canceled.rawValue {
|
|
52
|
+
let result = CredentialFactory.fromCancelled()
|
|
53
|
+
self.resolve?(result)
|
|
54
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
55
|
+
} else {
|
|
56
|
+
self.reject?(CredentialError.invalidResult.rawValue, error.localizedDescription, error)
|
|
57
|
+
self.emitEvent?("onCredentialFailure", [
|
|
58
|
+
"code": CredentialError.invalidResult.rawValue,
|
|
59
|
+
"message": error.localizedDescription
|
|
60
|
+
])
|
|
61
|
+
}
|
|
62
|
+
self.cleanup()
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
guard let user = result?.user else {
|
|
67
|
+
self.reject?(CredentialError.invalidResult.rawValue, "No user returned", nil)
|
|
68
|
+
self.emitEvent?("onCredentialFailure", [
|
|
69
|
+
"code": CredentialError.invalidResult.rawValue,
|
|
70
|
+
"message": "No user returned"
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
self.cleanup()
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let result = CredentialFactory.fromGoogleId(user: user)
|
|
78
|
+
self.resolve?(result)
|
|
79
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
80
|
+
self.cleanup()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import AuthenticationServices
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
public class HybridRetriever: RCTPromiseSettler,
|
|
5
|
+
ASAuthorizationControllerDelegate,
|
|
6
|
+
ASAuthorizationControllerPresentationContextProviding {
|
|
7
|
+
|
|
8
|
+
init(
|
|
9
|
+
clientId: String,
|
|
10
|
+
options: NSDictionary,
|
|
11
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
12
|
+
reject: @escaping RCTPromiseRejectBlock,
|
|
13
|
+
emitEvent: ((String, NSDictionary) -> Void)?
|
|
14
|
+
) {
|
|
15
|
+
super.init(resolve: resolve, reject: reject, emitEvent: emitEvent)
|
|
16
|
+
|
|
17
|
+
let controller = ASAuthorizationController(authorizationRequests: [
|
|
18
|
+
ASAuthorizationAppleIDProvider().createRequest(),
|
|
19
|
+
ASAuthorizationPasswordProvider().createRequest()
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
controller.delegate = self
|
|
23
|
+
controller.presentationContextProvider = self
|
|
24
|
+
|
|
25
|
+
if #available(iOS 16.0, *) {
|
|
26
|
+
controller.performRequests(options: .preferImmediatelyAvailableCredentials)
|
|
27
|
+
} else {
|
|
28
|
+
controller.performRequests()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
|
33
|
+
return UIWindow()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public func authorizationController(
|
|
37
|
+
controller: ASAuthorizationController,
|
|
38
|
+
didCompleteWithAuthorization authorization: ASAuthorization
|
|
39
|
+
) {
|
|
40
|
+
if let appleIdCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
|
41
|
+
let result = CredentialFactory.fromAppleId(appleIdCredential: appleIdCredential)
|
|
42
|
+
self.resolve?(result)
|
|
43
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
44
|
+
}
|
|
45
|
+
else if let credential = authorization.credential as? ASPasswordCredential {
|
|
46
|
+
let result = CredentialFactory.fromPassword(credential: credential)
|
|
47
|
+
self.resolve?(result)
|
|
48
|
+
self.emitEvent?("onCredentialSuccess", result as NSDictionary)
|
|
49
|
+
}
|
|
50
|
+
cleanup()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
|
54
|
+
self.reject?(
|
|
55
|
+
CredentialError.invalidResult.rawValue,
|
|
56
|
+
error.localizedDescription,
|
|
57
|
+
error
|
|
58
|
+
)
|
|
59
|
+
self.emitEvent?("onCredentialFailure", [
|
|
60
|
+
"code": CredentialError.invalidResult.rawValue,
|
|
61
|
+
"message": error.localizedDescription
|
|
62
|
+
])
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#import <OauthEssentialsSpec/OauthEssentialsSpec.h>
|
|
2
|
+
|
|
3
|
+
@interface OauthEssentials : NativeOauthEssentialsSpecBase <NativeOauthEssentialsSpec>
|
|
4
|
+
|
|
5
|
+
- (void)emitOnCredentialSuccess:(NSDictionary *)value;
|
|
6
|
+
- (void)emitOnCredentialFailure:(NSDictionary *)value;
|
|
7
|
+
|
|
8
|
+
@end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#import "OauthEssentials.h"
|
|
2
|
+
#import <AuthenticationServices/AuthenticationServices.h>
|
|
3
|
+
#import "OauthEssentials-Swift.h"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@implementation OauthEssentials {
|
|
7
|
+
OauthEssentialsModule *_sModule;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
- (instancetype)init
|
|
11
|
+
{
|
|
12
|
+
self = [super init];
|
|
13
|
+
if (self) {
|
|
14
|
+
__weak OauthEssentials *weakSelf = self;
|
|
15
|
+
|
|
16
|
+
_sModule = [[OauthEssentialsModule alloc]
|
|
17
|
+
initOnCredentialSuccess:^(NSDictionary * _Nonnull value) {
|
|
18
|
+
[weakSelf emitOnCredentialSuccess:value];
|
|
19
|
+
} onCredentialFailure:^(NSDictionary * _Nonnull value) {
|
|
20
|
+
[weakSelf emitOnCredentialSuccess:value];
|
|
21
|
+
}];
|
|
22
|
+
}
|
|
23
|
+
return self;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
27
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
28
|
+
{
|
|
29
|
+
return std::make_shared<facebook::react::NativeOauthEssentialsSpecJSI>(params);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
+ (NSString *)moduleName
|
|
33
|
+
{
|
|
34
|
+
return @"OauthEssentials";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Constants
|
|
38
|
+
- (NSDictionary *)getConstants
|
|
39
|
+
{
|
|
40
|
+
return [_sModule getConstants];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Methods
|
|
44
|
+
- (void)googleSignIn:(NSString *)clientId
|
|
45
|
+
options:(NSDictionary *)options
|
|
46
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
47
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
48
|
+
{
|
|
49
|
+
[_sModule googleSignIn:clientId
|
|
50
|
+
options:options
|
|
51
|
+
resolver:resolve
|
|
52
|
+
rejecter:reject];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
- (void)passwordSignIn:(NSString *)username
|
|
56
|
+
password:(NSString *)password
|
|
57
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
58
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
59
|
+
{
|
|
60
|
+
[_sModule passwordSignIn:username
|
|
61
|
+
password:password
|
|
62
|
+
resolver:resolve
|
|
63
|
+
rejecter:reject];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (void)getPassword:(RCTPromiseResolveBlock)resolve
|
|
67
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
68
|
+
{
|
|
69
|
+
[_sModule getPassword:resolve
|
|
70
|
+
rejecter:reject];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
- (void)hybridSignIn:(NSString *)clientId
|
|
75
|
+
options:(NSDictionary *)options
|
|
76
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
77
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
78
|
+
{
|
|
79
|
+
[_sModule hybridSignIn:clientId options:options resolver:resolve rejecter:reject];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
- (void)appleSignIn:(NSString *)webAndroidUrl
|
|
83
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
84
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
85
|
+
[_sModule appleSignIn:webAndroidUrl resolver:resolve rejecter:reject];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
- (void)createPassKey:(NSDictionary *)options
|
|
89
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
90
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
91
|
+
[_sModule createPassKey:options resolver:resolve rejecter:reject];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
- (void)getPassKey:(NSDictionary *)options
|
|
95
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
96
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
97
|
+
[_sModule getPassKey:options resolver:resolve rejecter:reject];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
- (facebook::react::ModuleConstants<JS::NativeOauthEssentials::Constants>) constantsToExport {
|
|
101
|
+
return (facebook::react::ModuleConstants<JS::NativeOauthEssentials::Constants>)[_sModule getConstants];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
import GoogleSignIn
|
|
4
|
+
import AuthenticationServices
|
|
5
|
+
import Security
|
|
6
|
+
import UIKit
|
|
7
|
+
|
|
8
|
+
public class OauthEssentialsModule: NSObject {
|
|
9
|
+
|
|
10
|
+
public var onCredentialSuccess: ((NSDictionary) -> Void)?
|
|
11
|
+
public var onCredentialFailure: ((NSDictionary) -> Void)?
|
|
12
|
+
|
|
13
|
+
private var _password_retriever: PasswordRetriever? = nil
|
|
14
|
+
private var _google_id_retriever: GoogleIdRetriever? = nil
|
|
15
|
+
private var _apple_id_retriever: AppleIdRetriever? = nil
|
|
16
|
+
private var _hybrid_retriever: HybridRetriever? = nil
|
|
17
|
+
private var _passkey_retriever: RCTPromiseSettler? = nil
|
|
18
|
+
|
|
19
|
+
@objc
|
|
20
|
+
public init(
|
|
21
|
+
onCredentialSuccess: @escaping ((NSDictionary) -> Void),
|
|
22
|
+
onCredentialFailure: @escaping ((NSDictionary) -> Void)
|
|
23
|
+
) {
|
|
24
|
+
super.init()
|
|
25
|
+
|
|
26
|
+
self.onCredentialSuccess = onCredentialSuccess
|
|
27
|
+
self.onCredentialFailure = onCredentialFailure
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private func ensurePreviousPromiseSettled(settler: RCTPromiseSettler?, reject: RCTPromiseRejectBlock) -> Bool {
|
|
31
|
+
if settler == nil || (settler != nil && ((settler?.settled()) != nil)) {
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
reject(
|
|
36
|
+
CredentialError.simultaneousCallError.rawValue,
|
|
37
|
+
"Another operation is in progress",
|
|
38
|
+
nil
|
|
39
|
+
)
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@objc(requiresMainQueueSetup)
|
|
44
|
+
static func requiresMainQueueSetup() -> Bool { true }
|
|
45
|
+
|
|
46
|
+
@objc
|
|
47
|
+
public func getConstants() -> [String: Any] {
|
|
48
|
+
var googleIdSupported: Bool = false
|
|
49
|
+
var appleIdSupported: Bool = false
|
|
50
|
+
var passwordSupported: Bool = false
|
|
51
|
+
var passkeySupported = false
|
|
52
|
+
if #available(iOS 13.0, *) {
|
|
53
|
+
// Modern GoogleSignIn works on iOS 13+
|
|
54
|
+
googleIdSupported = true
|
|
55
|
+
appleIdSupported = true
|
|
56
|
+
passwordSupported = true
|
|
57
|
+
}
|
|
58
|
+
if #available(iOS 16.0, *) {
|
|
59
|
+
passkeySupported = true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return [
|
|
63
|
+
"GOOGLE_ID_SUPPORTED": googleIdSupported,
|
|
64
|
+
"PASSWORD_SUPPORTED": passwordSupported,
|
|
65
|
+
"GOOGLE_PLAY_SERVICES_SUPPORTED": false, // Not applicable on iOS, it does not have Google Play Services
|
|
66
|
+
"APPLE_ID_SUPPORTED": appleIdSupported,
|
|
67
|
+
"HYBRID_SUPPORTED": true,
|
|
68
|
+
"PASSKEY_SUPPORTED": passkeySupported
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@objc
|
|
73
|
+
public func googleSignIn(
|
|
74
|
+
_ clientId: String,
|
|
75
|
+
options: NSDictionary,
|
|
76
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
77
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
78
|
+
) {
|
|
79
|
+
if (ensurePreviousPromiseSettled(settler: self._google_id_retriever,reject: reject)) {
|
|
80
|
+
self._google_id_retriever = GoogleIdRetriever(clientId: clientId, options: options,resolve: resolve,reject: reject, emitEvent: emitEvent)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@objc
|
|
85
|
+
public func passwordSignIn(
|
|
86
|
+
_ username: String,
|
|
87
|
+
password: String,
|
|
88
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
89
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
90
|
+
) {
|
|
91
|
+
if (ensurePreviousPromiseSettled(settler: self._apple_id_retriever, reject: reject)) {
|
|
92
|
+
self._apple_id_retriever = AppleIdRetriever(resolve: resolve, reject: reject, emitEvent: self.emitEvent)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@objc
|
|
97
|
+
public func getPassword(
|
|
98
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
99
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
100
|
+
) {
|
|
101
|
+
if (ensurePreviousPromiseSettled(settler: self._password_retriever,reject: reject)) {
|
|
102
|
+
self._password_retriever = PasswordRetriever(resolve: resolve,reject: reject, emitEvent: self.emitEvent)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@objc
|
|
107
|
+
public func hybridSignIn(
|
|
108
|
+
_ clientId: String,
|
|
109
|
+
options: NSDictionary,
|
|
110
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
111
|
+
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
112
|
+
if (ensurePreviousPromiseSettled(settler: self._hybrid_retriever,reject: reject)) {
|
|
113
|
+
self._hybrid_retriever = HybridRetriever(clientId: clientId, options: options, resolve: resolve, reject: reject, emitEvent: emitEvent)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@objc(createPassKey:resolver:rejecter:)
|
|
118
|
+
public func createPassKey(
|
|
119
|
+
_ options: NSDictionary,
|
|
120
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
121
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
122
|
+
) {
|
|
123
|
+
guard #available(iOS 16.0, *) else {
|
|
124
|
+
reject(
|
|
125
|
+
CredentialError.notSupportedError.rawValue,
|
|
126
|
+
"Passkeys require iOS 16.0 or later",
|
|
127
|
+
nil
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ensurePreviousPromiseSettled(settler: self._passkey_retriever, reject: reject) {
|
|
133
|
+
guard let requestJson = options["requestJson"] as? String else {
|
|
134
|
+
reject(
|
|
135
|
+
CredentialError.invalidResult.rawValue,
|
|
136
|
+
"\"requestJson\" field is required",
|
|
137
|
+
nil
|
|
138
|
+
)
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
self._passkey_retriever = PasskeyRetriever(
|
|
143
|
+
requestJson: requestJson,
|
|
144
|
+
mode: .registration,
|
|
145
|
+
resolve: resolve,
|
|
146
|
+
reject: reject,
|
|
147
|
+
emitEvent: emitEvent
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@objc(getPassKey:resolver:rejecter:)
|
|
153
|
+
public func getPassKey(
|
|
154
|
+
_ options: NSDictionary,
|
|
155
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
156
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
157
|
+
) {
|
|
158
|
+
guard #available(iOS 16.0, *) else {
|
|
159
|
+
reject(
|
|
160
|
+
CredentialError.notSupportedError.rawValue,
|
|
161
|
+
"Passkeys require iOS 16.0 or later",
|
|
162
|
+
nil
|
|
163
|
+
)
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if ensurePreviousPromiseSettled(settler: self._passkey_retriever, reject: reject) {
|
|
168
|
+
guard let requestJson = options["requestJson"] as? String else {
|
|
169
|
+
reject(
|
|
170
|
+
CredentialError.invalidResult.rawValue,
|
|
171
|
+
"\"requestJson\" field is required",
|
|
172
|
+
nil
|
|
173
|
+
)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
self._passkey_retriever = PasskeyRetriever(
|
|
178
|
+
requestJson: requestJson,
|
|
179
|
+
mode: .assertion,
|
|
180
|
+
resolve: resolve,
|
|
181
|
+
reject: reject,
|
|
182
|
+
emitEvent: emitEvent
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@objc(appleSignIn:resolver:rejecter:)
|
|
188
|
+
public func appleSignIn(
|
|
189
|
+
_ webAndroidUrl: String,
|
|
190
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
191
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
192
|
+
) {
|
|
193
|
+
if (ensurePreviousPromiseSettled(settler: self._apple_id_retriever,reject: reject)) {
|
|
194
|
+
self._apple_id_retriever = AppleIdRetriever(resolve: resolve,reject: reject, emitEvent: emitEvent)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private func emitEvent(eventName: String, body: NSDictionary) {
|
|
199
|
+
switch eventName {
|
|
200
|
+
case "onCredentialSuccess":
|
|
201
|
+
onCredentialSuccess?(body)
|
|
202
|
+
|
|
203
|
+
case "onCredentialFailure":
|
|
204
|
+
onCredentialFailure?(body)
|
|
205
|
+
|
|
206
|
+
default:
|
|
207
|
+
print("Unhandled event found: \(eventName)")
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|