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.
Files changed (41) hide show
  1. package/LICENSE +20 -0
  2. package/OauthEssentials.podspec +22 -0
  3. package/README.md +30 -0
  4. package/android/build.gradle +74 -0
  5. package/android/src/main/AndroidManifest.xml +22 -0
  6. package/android/src/main/java/com/oauthessentials/CredentialError.kt +7 -0
  7. package/android/src/main/java/com/oauthessentials/CredentialFactory.kt +114 -0
  8. package/android/src/main/java/com/oauthessentials/CustomTabsActivity.kt +133 -0
  9. package/android/src/main/java/com/oauthessentials/OauthEssentialsModule.kt +603 -0
  10. package/android/src/main/java/com/oauthessentials/OauthEssentialsPackage.kt +33 -0
  11. package/android/src/main/java/com/oauthessentials/RCTPromiseSettler.kt +60 -0
  12. package/ios/AppleIdRetriever.swift +61 -0
  13. package/ios/CredentialError.swift +6 -0
  14. package/ios/CredentialFactory.swift +133 -0
  15. package/ios/CredentialsType.swift +7 -0
  16. package/ios/GoogleIdRetriever.swift +83 -0
  17. package/ios/HybridRetriever.swift +64 -0
  18. package/ios/OauthEssentials.h +8 -0
  19. package/ios/OauthEssentials.mm +104 -0
  20. package/ios/OauthEssentialsModule.swift +210 -0
  21. package/ios/PasskeyRetriever.swift +226 -0
  22. package/ios/PasswordRetriever.swift +72 -0
  23. package/ios/RCTPromiseSettler.swift +28 -0
  24. package/lib/module/NativeOauthEssentials.js +5 -0
  25. package/lib/module/NativeOauthEssentials.js.map +1 -0
  26. package/lib/module/index.js +148 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/package.json +1 -0
  29. package/lib/module/types.js +23 -0
  30. package/lib/module/types.js.map +1 -0
  31. package/lib/typescript/package.json +1 -0
  32. package/lib/typescript/src/NativeOauthEssentials.d.ts +60 -0
  33. package/lib/typescript/src/NativeOauthEssentials.d.ts.map +1 -0
  34. package/lib/typescript/src/index.d.ts +78 -0
  35. package/lib/typescript/src/index.d.ts.map +1 -0
  36. package/lib/typescript/src/types.d.ts +71 -0
  37. package/lib/typescript/src/types.d.ts.map +1 -0
  38. package/package.json +156 -0
  39. package/src/NativeOauthEssentials.ts +75 -0
  40. package/src/index.tsx +199 -0
  41. package/src/types.ts +79 -0
@@ -0,0 +1,603 @@
1
+ package com.oauthessentials
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.BroadcastReceiver
5
+ import android.content.Context
6
+ import android.content.Intent
7
+ import android.content.IntentFilter
8
+ import android.net.Uri
9
+ import android.os.Build
10
+ import android.util.Log
11
+ import android.util.Patterns
12
+ import androidx.annotation.RequiresApi
13
+ import androidx.core.content.ContextCompat
14
+ import androidx.core.net.toUri
15
+ import androidx.credentials.CreatePasswordRequest
16
+ import androidx.credentials.CreatePublicKeyCredentialRequest
17
+ import androidx.credentials.CredentialManager
18
+ import androidx.credentials.GetCredentialRequest
19
+ import androidx.credentials.GetPasswordOption
20
+ import androidx.credentials.GetPublicKeyCredentialOption
21
+ import androidx.credentials.exceptions.CreateCredentialCancellationException
22
+ import androidx.credentials.exceptions.GetCredentialCancellationException
23
+ import com.facebook.react.bridge.Arguments
24
+ import com.facebook.react.bridge.Promise
25
+ import com.facebook.react.bridge.ReactApplicationContext
26
+ import com.facebook.react.bridge.ReadableMap
27
+ import com.facebook.react.bridge.WritableMap
28
+ import com.google.android.gms.common.ConnectionResult
29
+ import com.google.android.gms.common.GoogleApiAvailability
30
+ import com.google.android.libraries.identity.googleid.GetGoogleIdOption
31
+ import kotlinx.coroutines.CoroutineScope
32
+ import kotlinx.coroutines.Dispatchers
33
+ import kotlinx.coroutines.Job
34
+ import kotlinx.coroutines.SupervisorJob
35
+ import kotlinx.coroutines.cancel
36
+ import kotlinx.coroutines.launch
37
+ import kotlinx.coroutines.withContext
38
+ import java.security.SecureRandom
39
+ import java.util.Base64
40
+ import java.util.UUID
41
+
42
+ class OauthEssentialsModule(reactContext: ReactApplicationContext) :
43
+ NativeOauthEssentialsSpec(reactContext) {
44
+
45
+ private var appleSignInPromiseSettler: RCTPromiseSettler? = null
46
+ private val moduleScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
47
+
48
+ private val receiver = object : BroadcastReceiver() {
49
+ override fun onReceive(context: Context?, intent: Intent?) {
50
+ intent?.action?.let { action ->
51
+ Log.d(LOG_TAG, "Handling intent action ${action} received")
52
+ when (action) {
53
+ WEB_APPLE_DEEP_LINK_RECEIVED_INTENT -> {
54
+ val url = intent.getStringExtra("url")
55
+ Log.d(LOG_TAG, "Receiving deep link ${url}")
56
+ intent.getStringExtra("url")?.let { url ->
57
+ val uri = url.toUri()
58
+ appleSignInPromiseSettler?.let {
59
+ if (!it.settled()) {
60
+ Log.d(LOG_TAG, "Sending deep link callback")
61
+ val result = Arguments.createMap().apply {
62
+ putString("type", CredentialFactory.CredentialsType.WEB_APPLE_ID.code)
63
+ putMap("data", Arguments.createMap().apply {
64
+ putString("url", uri.toString())
65
+ putString("scheme", uri.scheme)
66
+ putString("host", uri.host)
67
+ putString("path", uri.path)
68
+ putString("query", uri.query)
69
+ })
70
+ }
71
+ resolveAndEmit(result, it)
72
+ } else {
73
+ Log.d(LOG_TAG, "Cannot call deep link callback")
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ WEB_APPLE_CANCELLED_INTENT -> {
80
+ Log.d(LOG_TAG, "Receiving cancellation from CustomTabsActivity")
81
+ appleSignInPromiseSettler?.let {
82
+ if (!it.settled()) {
83
+ Log.d(LOG_TAG, "Sending cancellation callback")
84
+ resolveAndEmit(CredentialFactory.fromCancelled(), it)
85
+ } else {
86
+ Log.d(LOG_TAG, "Cannot call cancellation callback, promise already settled")
87
+ }
88
+ }
89
+ }
90
+
91
+ else -> {
92
+ throw IllegalArgumentException("Intent action not supported")
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ @SuppressLint("ObsoleteSdkInt")
100
+ override fun getTypedExportedConstants(): MutableMap<String, Boolean> {
101
+ hasGooglePlayServices()
102
+ val hasCredentialManager = getCredentialManagerSupported()
103
+ val constants: MutableMap<String, Boolean> = mutableMapOf(
104
+ "GOOGLE_PLAY_SERVICES_SUPPORTED" to hasGooglePlayServices(),
105
+ "PASSWORD_SUPPORTED" to hasCredentialManager,
106
+ "GOOGLE_ID_SUPPORTED" to googleIdSupported(),
107
+ "APPLE_ID_SUPPORTED" to getAppleIdSupported(),
108
+ "HYBRID_SUPPORTED" to hasCredentialManager,
109
+ "PASSKEYS_SUPPORTED" to getPasskeysSupported()
110
+ )
111
+ return constants
112
+ }
113
+
114
+ @RequiresApi(Build.VERSION_CODES.O)
115
+ override fun hybridSignIn(clientId: String, options: ReadableMap, promise: Promise) {
116
+ if (!hasGooglePlayServices()) {
117
+ rejectAndEmitEvent(
118
+ CredentialError.NOT_SUPPORTED_ERROR.code,
119
+ "Device does not have GooglePlay Services",
120
+ promise
121
+ )
122
+ return
123
+ }
124
+ if (!getCredentialManagerSupported()) {
125
+ rejectAndEmitEvent(
126
+ CredentialError.NOT_SUPPORTED_ERROR.code,
127
+ "Device does not support Credential Manager, only android >=12 allowed.",
128
+ promise
129
+ )
130
+ return
131
+ }
132
+
133
+ val activity = reactApplicationContext.currentActivity
134
+ if (activity == null) {
135
+ rejectAndEmitEvent(
136
+ CredentialError.NO_ACTIVITY_ERROR.code,
137
+ "Activity not available",
138
+ promise
139
+ )
140
+ return
141
+ }
142
+
143
+ moduleScope.launch {
144
+ try {
145
+ val manager = CredentialManager.create(activity)
146
+ val randomBytes = ByteArray(32)
147
+ SecureRandom.getInstanceStrong().nextBytes(randomBytes)
148
+ val randomNonce = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
149
+
150
+ val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
151
+ .setNonce(randomNonce)
152
+ .setServerClientId(clientId)
153
+ .setFilterByAuthorizedAccounts(options.getBoolean("authorizedAccounts"))
154
+ .setAutoSelectEnabled(options.getBoolean("autoSelectEnabled"))
155
+ .build()
156
+
157
+ val request: GetCredentialRequest = GetCredentialRequest.Builder()
158
+ .addCredentialOption(googleIdOption)
159
+ .addCredentialOption(GetPasswordOption())
160
+ .build()
161
+
162
+ resolveAndEmit(
163
+ CredentialFactory.fromCredentialResponse(
164
+ manager.getCredential(
165
+ request = request,
166
+ context = activity
167
+ )
168
+ ), promise
169
+ )
170
+ } catch (e: GetCredentialCancellationException) {
171
+ Log.d(LOG_TAG, e.toString())
172
+ resolveAndEmit(CredentialFactory.fromCancelled(), promise)
173
+ } catch (e: Throwable) {
174
+ Log.d(LOG_TAG, e.toString())
175
+ rejectAndEmitEvent(
176
+ CredentialError.INVALID_RESULT_ERROR.code,
177
+ e,
178
+ promise
179
+ )
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Performs the apple sign in.
186
+ * The signing in is redirecting to the device default browser to handle it.
187
+ */
188
+ @RequiresApi(Build.VERSION_CODES.O)
189
+ override fun appleSignIn(androidWebUrl: String?, promise: Promise) {
190
+ appleSignInPromiseSettler?.let {
191
+ if (!it.settled()) {
192
+ it.resolve(CredentialFactory.fromCancelled())
193
+ }
194
+ }
195
+ appleSignInPromiseSettler = null
196
+
197
+ val activity = this.reactApplicationContext.currentActivity
198
+ if (activity === null) {
199
+ rejectAndEmitEvent(
200
+ CredentialError.NO_ACTIVITY_ERROR.code,
201
+ "Could not find app activity.",
202
+ promise
203
+ )
204
+ return
205
+ }
206
+ var uri: Uri
207
+ try {
208
+ uri = parseWebUrl(androidWebUrl)
209
+ } catch (e: Throwable) {
210
+ rejectAndEmitEvent(CredentialError.INVALID_RESULT_ERROR.code, e, promise)
211
+ return
212
+ }
213
+
214
+ appleSignInPromiseSettler = RCTPromiseSettler(promise)
215
+ activity.runOnUiThread {
216
+ val intent = Intent(activity, CustomTabsActivity::class.java).apply {
217
+ data = uri
218
+ action = DISPLAY_CUSTOM_TABS_INTENT
219
+ }
220
+ activity.startActivity(intent)
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Performs the google sign in.
226
+ */
227
+ @Suppress("DEPRECATION")
228
+ @RequiresApi(Build.VERSION_CODES.O)
229
+ override fun googleSignIn(clientId: String, options: ReadableMap, promise: Promise) {
230
+ Log.d(LOG_TAG, "Calling googleSignIn")
231
+ if (!googleIdSupported() || !getCredentialManagerSupported()) {
232
+ rejectAndEmitEvent(
233
+ CredentialError.NOT_SUPPORTED_ERROR.code,
234
+ "Device does not support googleSignIn method.",
235
+ promise
236
+ )
237
+ return
238
+ }
239
+
240
+ val activity = reactApplicationContext.currentActivity
241
+ if (activity == null) {
242
+ rejectAndEmitEvent(CredentialError.NO_ACTIVITY_ERROR.code, "Activity not available", promise)
243
+ return
244
+ }
245
+
246
+ moduleScope.launch {
247
+ try {
248
+ val manager = CredentialManager.create(activity)
249
+
250
+ val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
251
+ .setNonce(UUID.randomUUID().toString())
252
+ .setServerClientId(clientId)
253
+ .setFilterByAuthorizedAccounts(options.getBoolean("authorizedAccounts"))
254
+ .setAutoSelectEnabled(options.getBoolean("autoSelectEnabled"))
255
+ .build()
256
+
257
+ val request: GetCredentialRequest = GetCredentialRequest.Builder()
258
+ .addCredentialOption(googleIdOption)
259
+ .build()
260
+
261
+ val result = withContext(Dispatchers.Main) {
262
+ manager.getCredential(activity, request)
263
+ }
264
+ resolveAndEmit(CredentialFactory.fromCredentialResponse(result), promise)
265
+ } catch (e: GetCredentialCancellationException) {
266
+ Log.d(LOG_TAG, e.toString())
267
+ resolveAndEmit(CredentialFactory.fromCancelled(), promise)
268
+ } catch (e: Throwable) {
269
+ rejectAndEmitEvent(CredentialError.INVALID_RESULT_ERROR.code, e.toString(), promise)
270
+ }
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Gets the user current credentials.
276
+ */
277
+ override fun getPassword(promise: Promise) {
278
+ if (!googleIdSupported()) {
279
+ rejectAndEmitEvent(
280
+ CredentialError.NOT_SUPPORTED_ERROR.code,
281
+ "Device does not support googleSignIn method.",
282
+ promise
283
+ )
284
+ return
285
+ }
286
+
287
+ val activity = reactApplicationContext.currentActivity
288
+ if (activity == null) {
289
+ rejectAndEmitEvent(
290
+ CredentialError.NO_ACTIVITY_ERROR.code,
291
+ "Activity not available",
292
+ promise
293
+ )
294
+ return
295
+ }
296
+
297
+ moduleScope.launch {
298
+ try {
299
+ val manager = CredentialManager.create(activity)
300
+ val request = GetCredentialRequest(
301
+ listOf(GetPasswordOption())
302
+ )
303
+
304
+ resolveAndEmit(
305
+ CredentialFactory.fromCredentialResponse(
306
+ manager.getCredential(
307
+ request = request,
308
+ context = activity
309
+ )
310
+ ), promise
311
+ )
312
+ } catch (e: Throwable) {
313
+ Log.d(LOG_TAG, e.toString())
314
+ promise.resolve(false)
315
+ }
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Stores a brand new username and password into the OS.
321
+ */
322
+ override fun passwordSignIn(username: String, password: String, promise: Promise) {
323
+ if (!googleIdSupported()) {
324
+ rejectAndEmitEvent(
325
+ CredentialError.NOT_SUPPORTED_ERROR.code,
326
+ "Device does not support googleSignIn method.",
327
+ promise
328
+ )
329
+ return
330
+ }
331
+
332
+ val activity = reactApplicationContext.currentActivity
333
+ if (activity == null) {
334
+ rejectAndEmitEvent(CredentialError.NO_ACTIVITY_ERROR.code, "Activity not available", promise)
335
+ return
336
+ }
337
+
338
+ moduleScope.launch {
339
+ try {
340
+ val manager = CredentialManager.create(activity)
341
+ val request = CreatePasswordRequest(
342
+ id = username,
343
+ password = password
344
+ )
345
+
346
+ manager.createCredential(
347
+ request = request,
348
+ context = activity
349
+ )
350
+ promise.resolve(true)
351
+ } catch (e: Throwable) {
352
+ Log.e(LOG_TAG, e.toString())
353
+ promise.resolve(false)
354
+ }
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Creates the passkey.
360
+ */
361
+ @RequiresApi(Build.VERSION_CODES.P)
362
+ override fun createPassKey(options: ReadableMap, promise: Promise) {
363
+ if (!getPasskeysSupported()) {
364
+ rejectAndEmitEvent(
365
+ CredentialError.NOT_SUPPORTED_ERROR.code,
366
+ "Device does not support googleSignIn method.",
367
+ promise
368
+ )
369
+ return
370
+ }
371
+
372
+ val activity = reactApplicationContext.currentActivity
373
+ if (activity == null) {
374
+ rejectAndEmitEvent(CredentialError.NO_ACTIVITY_ERROR.code, "Activity not available", promise)
375
+ return
376
+ }
377
+
378
+ moduleScope.launch {
379
+ try {
380
+ val requestJson = options.getString("requestJson")
381
+ ?: throw IllegalArgumentException("\"requestJson\" field should be set on android.")
382
+ var preferImmediatelyAvailableCredentials = false
383
+ if (options.hasKey("preferImmediatelyAvailableCredentials")) {
384
+ preferImmediatelyAvailableCredentials =
385
+ options.getBoolean("preferImmediatelyAvailableCredentials")
386
+ }
387
+ var isConditional = false
388
+ if (options.hasKey("isConditional")) {
389
+ isConditional = options.getBoolean("isConditional")
390
+ }
391
+
392
+ val manager = CredentialManager.create(activity)
393
+ val request = CreatePublicKeyCredentialRequest(
394
+ requestJson = requestJson,
395
+ preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
396
+ isConditional = isConditional
397
+ )
398
+ val result = manager.createCredential(
399
+ request = request,
400
+ context = activity
401
+ )
402
+ resolveAndEmit(CredentialFactory.fromPublicKeyCredential(result), promise)
403
+ } catch (e: Throwable) {
404
+ when (e) {
405
+ is CreateCredentialCancellationException -> {
406
+ resolveAndEmit(CredentialFactory.fromCancelled(), promise)
407
+ }
408
+
409
+ else -> {
410
+ Log.e(LOG_TAG, e.toString())
411
+ rejectAndEmitEvent(CredentialError.INVALID_RESULT_ERROR.code, e.toString(), promise)
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Gets the passkey.
420
+ */
421
+ @RequiresApi(Build.VERSION_CODES.P)
422
+ override fun getPassKey(options: ReadableMap, promise: Promise) {
423
+ if (!getPasskeysSupported()) {
424
+ rejectAndEmitEvent(
425
+ CredentialError.NOT_SUPPORTED_ERROR.code,
426
+ "Device does not support googleSignIn method.",
427
+ promise
428
+ )
429
+ return
430
+ }
431
+
432
+ val activity = reactApplicationContext.currentActivity
433
+ if (activity == null) {
434
+ rejectAndEmitEvent(CredentialError.NO_ACTIVITY_ERROR.code, "Activity not available", promise)
435
+ return
436
+ }
437
+
438
+ moduleScope.launch {
439
+ try {
440
+ val requestJson = options.getString("requestJson")
441
+ ?: throw IllegalArgumentException("\"requestJson\" field should be set on android.")
442
+ var preferImmediatelyAvailableCredentials = false
443
+ if (options.hasKey("preferImmediatelyAvailableCredentials")) {
444
+ preferImmediatelyAvailableCredentials =
445
+ options.getBoolean("preferImmediatelyAvailableCredentials")
446
+ }
447
+
448
+ val manager = CredentialManager.create(activity)
449
+ val request = GetCredentialRequest(
450
+ listOf(
451
+ GetPublicKeyCredentialOption(
452
+ requestJson = requestJson,
453
+ ),
454
+ ),
455
+ preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
456
+ )
457
+ val result = manager.getCredential(
458
+ request = request,
459
+ context = activity
460
+ )
461
+ resolveAndEmit(CredentialFactory.fromPublicKeyCredential(result), promise)
462
+ } catch (e: Throwable) {
463
+ when (e) {
464
+ is CreateCredentialCancellationException -> {
465
+ resolveAndEmit(CredentialFactory.fromCancelled(), promise)
466
+ }
467
+
468
+ else -> {
469
+ Log.e(LOG_TAG, e.toString())
470
+ rejectAndEmitEvent(CredentialError.INVALID_RESULT_ERROR.code, e.toString(), promise)
471
+ }
472
+ }
473
+ }
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Gets if has google play services.
479
+ */
480
+ private fun hasGooglePlayServices(): Boolean {
481
+ val result = GoogleApiAvailability.getInstance()
482
+ .isGooglePlayServicesAvailable(reactApplicationContext)
483
+ return result == ConnectionResult.SUCCESS
484
+ }
485
+
486
+ @RequiresApi(Build.VERSION_CODES.O)
487
+ override fun initialize() {
488
+ super.initialize()
489
+
490
+ Log.d(LOG_TAG, "Initialize has been called")
491
+ Log.d(LOG_TAG, "Registering deep link broadcast receiver")
492
+ ContextCompat.registerReceiver(
493
+ reactApplicationContext.applicationContext,
494
+ receiver,
495
+ IntentFilter().apply {
496
+ addAction(WEB_APPLE_DEEP_LINK_RECEIVED_INTENT)
497
+ addAction(WEB_APPLE_CANCELLED_INTENT)
498
+ },
499
+ ContextCompat.RECEIVER_NOT_EXPORTED
500
+ )
501
+ }
502
+
503
+ override fun invalidate() {
504
+ super.invalidate()
505
+ Log.d(LOG_TAG, "Invalidate has been called")
506
+
507
+ Log.d(LOG_TAG, "Cancelling all coroutines and credential operations")
508
+ moduleScope.cancel()
509
+
510
+ appleSignInPromiseSettler?.let {
511
+ if (!it.settled()) {
512
+ Log.d(LOG_TAG, "Rejecting pending Apple sign-in promise without event")
513
+ it.reject(
514
+ "CANCELLED",
515
+ "Module is being invalidated",
516
+ null,
517
+ null
518
+ )
519
+ }
520
+ }
521
+ appleSignInPromiseSettler = null
522
+
523
+ Log.d(LOG_TAG, "Unregistering deep link broadcast receiver")
524
+ reactApplicationContext.unregisterReceiver(receiver)
525
+ }
526
+
527
+ /**
528
+ * Parses the web url.
529
+ */
530
+ private fun parseWebUrl(url: String?): Uri {
531
+ val url = url?.trim()
532
+ ?: throw IllegalArgumentException("URL cannot be null")
533
+
534
+ if (!Patterns.WEB_URL.matcher(url).matches()) {
535
+ throw IllegalArgumentException("Invalid URL format: $url")
536
+ }
537
+
538
+ return url.toUri()
539
+ }
540
+
541
+ private fun googleIdSupported(): Boolean = hasGooglePlayServices()
542
+
543
+ private fun getAppleIdSupported(): Boolean = true
544
+
545
+ private fun getCredentialManagerSupported(): Boolean = true
546
+
547
+ private fun getPasskeysSupported(): Boolean {
548
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && getCredentialManagerSupported()
549
+ }
550
+
551
+ /**
552
+ * Reject and emit event.
553
+ */
554
+ private fun rejectAndEmitEvent(code: String, e: Throwable, promise: Promise) {
555
+ promise.reject(code, e)
556
+
557
+ val error = Arguments.createMap()
558
+ error.putString("code", code)
559
+ error.putString("message", e.toString())
560
+ }
561
+
562
+ /**
563
+ * Reject and emit event.
564
+ */
565
+ private fun rejectAndEmitEvent(code: String, e: String, promise: Promise) {
566
+ promise.reject(code, e)
567
+
568
+ val error = Arguments.createMap()
569
+ error.putString("code", code)
570
+ error.putString("message", e)
571
+ emitOnCredentialFailure(error)
572
+ }
573
+
574
+ /**
575
+ * Resolves and emit event.
576
+ */
577
+ private fun resolveAndEmit(data: WritableMap, promise: Promise) {
578
+ promise.resolve(data.copy())
579
+ emitOnCredentialSuccess(data)
580
+ }
581
+
582
+ /**
583
+ * Resolves and emit event.
584
+ */
585
+ private fun resolveAndEmit(data: WritableMap, settler: RCTPromiseSettler) {
586
+ settler.resolve(data.copy())
587
+ emitOnCredentialSuccess(data)
588
+ Log.d(LOG_TAG, "Resolving event emitOnCredentialSuccess")
589
+ }
590
+
591
+ companion object {
592
+ const val NAME = NativeOauthEssentialsSpec.NAME
593
+
594
+ const val LOG_TAG = "NativeOauthEssentials"
595
+
596
+ // Apple OAuth intents
597
+ const val WEB_APPLE_DEEP_LINK_RECEIVED_INTENT =
598
+ "com.oauthessentials.WEB_APPLE_DEEP_LINK_RECEIVED_INTENT"
599
+ const val WEB_APPLE_CANCELLED_INTENT =
600
+ "com.oauthessentials.WEB_APPLE_CANCELLED_INTENT"
601
+ const val DISPLAY_CUSTOM_TABS_INTENT = "com.oauthessentials.DISPLAY_CUSTOM_TABS_INTENT"
602
+ }
603
+ }
@@ -0,0 +1,33 @@
1
+ package com.oauthessentials
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class OauthEssentialsPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == OauthEssentialsModule.NAME) {
13
+ OauthEssentialsModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
20
+ return ReactModuleInfoProvider {
21
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
22
+ moduleInfos[OauthEssentialsModule.NAME] = ReactModuleInfo(
23
+ OauthEssentialsModule.NAME,
24
+ OauthEssentialsModule.NAME,
25
+ false, // canOverrideExistingModule
26
+ false, // needsEagerInit
27
+ false, // isCxxModule
28
+ true // isTurboModule
29
+ )
30
+ moduleInfos
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,60 @@
1
+ package com.oauthessentials
2
+
3
+ import com.facebook.react.bridge.Promise
4
+ import com.facebook.react.bridge.WritableMap
5
+
6
+ class RCTPromiseSettler(private val promise: Promise) {
7
+ private var settled = false
8
+
9
+ fun settled(): Boolean {
10
+ return settled
11
+ }
12
+
13
+ fun resolve(value: Any) {
14
+ if (settled) {
15
+ throw IllegalStateException("Cannot resolve an already settled promise.")
16
+ }
17
+ settled = true
18
+ promise.resolve(value)
19
+ }
20
+
21
+ fun reject(throwable: Throwable, userInfo: WritableMap) {
22
+ if (settled) {
23
+ throw IllegalStateException("Cannot reject an already settled promise.")
24
+ }
25
+ settled = true
26
+ promise.reject(throwable, userInfo)
27
+ }
28
+
29
+ fun reject(code: String, userInfo: WritableMap) {
30
+ if (settled) {
31
+ throw IllegalStateException("Cannot reject an already settled promise.")
32
+ }
33
+ settled = true
34
+ promise.reject(code, userInfo)
35
+ }
36
+
37
+ fun reject(code: String, throwable: Throwable?, userInfo: WritableMap) {
38
+ if (settled) {
39
+ throw IllegalStateException("Cannot reject an already settled promise.")
40
+ }
41
+ settled = true
42
+ promise.reject(code, throwable, userInfo)
43
+ }
44
+
45
+ fun reject(code: String, message: String?, userInfo: WritableMap) {
46
+ if (settled) {
47
+ throw IllegalStateException("Cannot reject an already settled promise.")
48
+ }
49
+ settled = true
50
+ promise.reject(code, message, userInfo)
51
+ }
52
+
53
+ fun reject(code: String?, message: String?, throwable: Throwable?, userInfo: WritableMap?) {
54
+ if (settled) {
55
+ throw IllegalStateException("Cannot reject an already settled promise.")
56
+ }
57
+ settled = true
58
+ promise.reject(code, message, throwable, userInfo)
59
+ }
60
+ }