react-native-authsignal 1.0.13 → 1.1.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/android/build.gradle +27 -87
- package/android/gradle/wrapper/gradle-wrapper.properties +3 -2
- package/android/gradle.properties +4 -3
- package/android/src/main/java/com/authsignal/react/AuthenticationActivity.kt +69 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalEmailModule.kt +113 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalModule.kt +115 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalPackage.kt +23 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalPasskeyModule.kt +103 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalPushModule.kt +152 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalSMSModule.kt +117 -0
- package/android/src/main/java/com/authsignal/react/AuthsignalTOTPModule.kt +95 -0
- package/android/src/main/java/com/authsignal/react/RedirectActivity.kt +17 -0
- package/package.json +1 -1
- package/android/src/main/java/com/authsignal/react/AuthenticationActivity.java +0 -73
- package/android/src/main/java/com/authsignal/react/AuthsignalEmailModule.java +0 -139
- package/android/src/main/java/com/authsignal/react/AuthsignalModule.java +0 -127
- package/android/src/main/java/com/authsignal/react/AuthsignalPackage.java +0 -29
- package/android/src/main/java/com/authsignal/react/AuthsignalPasskeyModule.java +0 -133
- package/android/src/main/java/com/authsignal/react/AuthsignalPushModule.java +0 -188
- package/android/src/main/java/com/authsignal/react/AuthsignalSMSModule.java +0 -139
- package/android/src/main/java/com/authsignal/react/AuthsignalTOTPModule.java +0 -116
- package/android/src/main/java/com/authsignal/react/RedirectActivity.java +0 -18
package/android/build.gradle
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
+
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["Authsignal_kotlinVersion"]
|
|
3
|
+
|
|
2
4
|
repositories {
|
|
3
5
|
google()
|
|
4
6
|
mavenCentral()
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
dependencies {
|
|
8
|
-
classpath 'com.android.tools.build:gradle:
|
|
10
|
+
classpath 'com.android.tools.build:gradle:8.1.4'
|
|
11
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
9
12
|
}
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
def isNewArchitectureEnabled() {
|
|
13
|
-
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
14
|
-
}
|
|
15
|
-
|
|
16
15
|
apply plugin: 'com.android.library'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (isNewArchitectureEnabled()) {
|
|
20
|
-
apply plugin: 'com.facebook.react'
|
|
21
|
-
}
|
|
16
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
22
17
|
|
|
23
18
|
def getExtOrDefault(name) {
|
|
24
19
|
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Authsignal_' + name]
|
|
@@ -29,13 +24,21 @@ def getExtOrIntegerDefault(name) {
|
|
|
29
24
|
}
|
|
30
25
|
|
|
31
26
|
android {
|
|
27
|
+
namespace "com.authsignal"
|
|
28
|
+
|
|
29
|
+
sourceSets {
|
|
30
|
+
main {
|
|
31
|
+
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
32
35
|
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
|
|
33
36
|
|
|
34
37
|
defaultConfig {
|
|
35
38
|
minSdkVersion getExtOrIntegerDefault('minSdkVersion')
|
|
36
39
|
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
|
|
37
|
-
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
38
40
|
}
|
|
41
|
+
|
|
39
42
|
buildTypes {
|
|
40
43
|
release {
|
|
41
44
|
minifyEnabled false
|
|
@@ -47,95 +50,32 @@ android {
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
compileOptions {
|
|
50
|
-
sourceCompatibility JavaVersion.
|
|
51
|
-
targetCompatibility JavaVersion.
|
|
53
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
54
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
kotlinOptions {
|
|
58
|
+
jvmTarget = '17'
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
buildFeatures {
|
|
62
|
+
buildConfig true
|
|
63
|
+
}
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
repositories {
|
|
57
67
|
mavenCentral()
|
|
58
68
|
google()
|
|
59
|
-
|
|
60
|
-
def found = false
|
|
61
|
-
def defaultDir = null
|
|
62
|
-
def androidSourcesName = 'React Native sources'
|
|
63
|
-
|
|
64
|
-
if (rootProject.ext.has('reactNativeAndroidRoot')) {
|
|
65
|
-
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
|
|
66
|
-
} else {
|
|
67
|
-
defaultDir = new File(
|
|
68
|
-
projectDir,
|
|
69
|
-
'/../../../node_modules/react-native/android'
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (defaultDir.exists()) {
|
|
74
|
-
maven {
|
|
75
|
-
url defaultDir.toString()
|
|
76
|
-
name androidSourcesName
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
|
|
80
|
-
found = true
|
|
81
|
-
} else {
|
|
82
|
-
def parentDir = rootProject.projectDir
|
|
83
|
-
|
|
84
|
-
1.upto(5, {
|
|
85
|
-
if (found) return true
|
|
86
|
-
parentDir = parentDir.parentFile
|
|
87
|
-
|
|
88
|
-
def androidSourcesDir = new File(
|
|
89
|
-
parentDir,
|
|
90
|
-
'node_modules/react-native'
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
def androidPrebuiltBinaryDir = new File(
|
|
94
|
-
parentDir,
|
|
95
|
-
'node_modules/react-native/android'
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if (androidPrebuiltBinaryDir.exists()) {
|
|
99
|
-
maven {
|
|
100
|
-
url androidPrebuiltBinaryDir.toString()
|
|
101
|
-
name androidSourcesName
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
|
|
105
|
-
found = true
|
|
106
|
-
} else if (androidSourcesDir.exists()) {
|
|
107
|
-
maven {
|
|
108
|
-
url androidSourcesDir.toString()
|
|
109
|
-
name androidSourcesName
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
|
|
113
|
-
found = true
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!found) {
|
|
119
|
-
throw new GradleException(
|
|
120
|
-
"${project.name}: unable to locate React Native android sources. " +
|
|
121
|
-
"Ensure you have you installed React Native as a dependency in your project and try again."
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
69
|
}
|
|
125
70
|
|
|
71
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
72
|
+
|
|
126
73
|
dependencies {
|
|
127
74
|
//noinspection GradleDynamicVersion
|
|
128
75
|
implementation "com.facebook.react:react-native:+"
|
|
76
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
129
77
|
|
|
130
78
|
implementation "androidx.browser:browser:1.2.0"
|
|
131
79
|
|
|
132
|
-
implementation("com.authsignal:authsignal-android:1.
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (isNewArchitectureEnabled()) {
|
|
136
|
-
react {
|
|
137
|
-
jsRootDir = file("../src/")
|
|
138
|
-
libraryName = "Authsignal"
|
|
139
|
-
codegenJavaPackageName = "com.reactnativeauthsignal"
|
|
140
|
-
}
|
|
80
|
+
implementation("com.authsignal:authsignal-android:1.1.2")
|
|
141
81
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
#Fri Aug 16 14:14:32 NZST 2024
|
|
2
1
|
distributionBase=GRADLE_USER_HOME
|
|
3
2
|
distributionPath=wrapper/dists
|
|
4
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-
|
|
3
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
|
|
4
|
+
networkTimeout=10000
|
|
5
|
+
validateDistributionUrl=true
|
|
5
6
|
zipStoreBase=GRADLE_USER_HOME
|
|
6
7
|
zipStorePath=wrapper/dists
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
Authsignal_kotlinVersion=1.9.24
|
|
1
2
|
Authsignal_minSdkVersion=24
|
|
2
|
-
Authsignal_targetSdkVersion=
|
|
3
|
-
Authsignal_compileSdkVersion=
|
|
4
|
-
Authsignal_ndkversion=
|
|
3
|
+
Authsignal_targetSdkVersion=34
|
|
4
|
+
Authsignal_compileSdkVersion=34
|
|
5
|
+
Authsignal_ndkversion=26.1.10909125
|
|
5
6
|
android.useAndroidX=true
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package com.authsignal.react
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import android.os.Bundle
|
|
7
|
+
import androidx.browser.customtabs.CustomTabsIntent
|
|
8
|
+
|
|
9
|
+
class AuthenticationActivity : Activity() {
|
|
10
|
+
private var intentLaunched = false
|
|
11
|
+
|
|
12
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
13
|
+
super.onCreate(savedInstanceState)
|
|
14
|
+
if (savedInstanceState != null) {
|
|
15
|
+
intentLaunched = savedInstanceState.getBoolean(EXTRA_INTENT_LAUNCHED, false)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun onResume() {
|
|
20
|
+
super.onResume()
|
|
21
|
+
val authenticationIntent = intent
|
|
22
|
+
|
|
23
|
+
if (!intentLaunched && authenticationIntent.extras == null) {
|
|
24
|
+
finish()
|
|
25
|
+
return
|
|
26
|
+
} else if (!intentLaunched) {
|
|
27
|
+
intentLaunched = true
|
|
28
|
+
launchAuthenticationIntent()
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
val resultMissing = authenticationIntent.data == null
|
|
33
|
+
if (resultMissing) setResult(RESULT_CANCELED)
|
|
34
|
+
else setResult(RESULT_OK, authenticationIntent)
|
|
35
|
+
finish()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override fun onSaveInstanceState(outState: Bundle) {
|
|
39
|
+
super.onSaveInstanceState(outState)
|
|
40
|
+
outState.putBoolean(EXTRA_INTENT_LAUNCHED, intentLaunched)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun onNewIntent(intent: Intent?) {
|
|
44
|
+
super.onNewIntent(intent)
|
|
45
|
+
setIntent(intent)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private fun launchAuthenticationIntent() {
|
|
49
|
+
val extras = intent.extras
|
|
50
|
+
val authorizeUri = extras!!.getParcelable<Uri>(EXTRA_AUTHORIZE_URI)
|
|
51
|
+
val builder = CustomTabsIntent.Builder()
|
|
52
|
+
val customTabsIntent = builder.build()
|
|
53
|
+
customTabsIntent.launchUrl(this, authorizeUri!!)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
companion object {
|
|
57
|
+
const val AUTHENTICATION_REQUEST: Int = 1000
|
|
58
|
+
const val EXTRA_AUTHORIZE_URI: String = "com.authsignal.react.EXTRA_AUTHORIZE_URI"
|
|
59
|
+
private const val EXTRA_INTENT_LAUNCHED = "com.authsignal.react.EXTRA_INTENT_LAUNCHED"
|
|
60
|
+
|
|
61
|
+
@JvmStatic
|
|
62
|
+
fun authenticateUsingBrowser(activity: Activity, authorizeUri: Uri) {
|
|
63
|
+
val intent = Intent(activity, AuthenticationActivity::class.java)
|
|
64
|
+
intent.putExtra(EXTRA_AUTHORIZE_URI, authorizeUri)
|
|
65
|
+
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
66
|
+
activity.startActivityForResult(intent, AUTHENTICATION_REQUEST)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
package com.authsignal.react
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.authsignal.email.AuthsignalEmail
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.Promise
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
9
|
+
import com.facebook.react.bridge.ReactMethod
|
|
10
|
+
import kotlinx.coroutines.CoroutineScope
|
|
11
|
+
import kotlinx.coroutines.Dispatchers
|
|
12
|
+
import kotlinx.coroutines.SupervisorJob
|
|
13
|
+
import kotlinx.coroutines.launch
|
|
14
|
+
|
|
15
|
+
class AuthsignalEmailModule(private val reactContext: ReactApplicationContext) :
|
|
16
|
+
ReactContextBaseJavaModule(
|
|
17
|
+
reactContext
|
|
18
|
+
) {
|
|
19
|
+
private var authsignal: AuthsignalEmail? = null
|
|
20
|
+
|
|
21
|
+
private val defaultError = "unexpected_error"
|
|
22
|
+
|
|
23
|
+
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
|
24
|
+
|
|
25
|
+
override fun getConstants(): Map<String, Any>? {
|
|
26
|
+
val constants: MutableMap<String, Any> = HashMap()
|
|
27
|
+
constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
|
|
28
|
+
return constants
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override fun getName(): String {
|
|
32
|
+
return "AuthsignalEmailModule"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@ReactMethod
|
|
36
|
+
fun initialize(tenantID: String, baseURL: String, promise: Promise) {
|
|
37
|
+
val currentActivity = reactContext.currentActivity
|
|
38
|
+
|
|
39
|
+
if (currentActivity != null) {
|
|
40
|
+
authsignal = AuthsignalEmail(tenantID, baseURL)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
promise.resolve(null)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@ReactMethod
|
|
47
|
+
fun enroll(email: String, promise: Promise) {
|
|
48
|
+
launch(promise) {
|
|
49
|
+
val response = it.enroll(email)
|
|
50
|
+
|
|
51
|
+
if (response.error != null) {
|
|
52
|
+
val errorCode = response.errorType ?: defaultError
|
|
53
|
+
|
|
54
|
+
promise.reject(errorCode, response.error)
|
|
55
|
+
} else {
|
|
56
|
+
val enrollResponse = response.data
|
|
57
|
+
val map = Arguments.createMap()
|
|
58
|
+
map.putString("userAuthenticatorId", enrollResponse!!.userAuthenticatorId)
|
|
59
|
+
promise.resolve(map)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@ReactMethod
|
|
65
|
+
fun challenge(promise: Promise) {
|
|
66
|
+
launch(promise) {
|
|
67
|
+
val response = it.challenge()
|
|
68
|
+
|
|
69
|
+
if (response.error != null) {
|
|
70
|
+
val errorCode = response.errorType ?: defaultError
|
|
71
|
+
|
|
72
|
+
promise.reject(errorCode, response.error)
|
|
73
|
+
} else {
|
|
74
|
+
val challengeResponse = response.data
|
|
75
|
+
val map = Arguments.createMap()
|
|
76
|
+
map.putString("challengeId", challengeResponse!!.challengeId)
|
|
77
|
+
promise.resolve(map)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@ReactMethod
|
|
83
|
+
fun verify(code: String, promise: Promise) {
|
|
84
|
+
launch(promise) {
|
|
85
|
+
val response = it.verify(code)
|
|
86
|
+
|
|
87
|
+
if (response.error != null) {
|
|
88
|
+
val errorCode = response.errorType ?: defaultError
|
|
89
|
+
|
|
90
|
+
promise.reject(errorCode, response.error)
|
|
91
|
+
} else {
|
|
92
|
+
val verifyResponse = response.data
|
|
93
|
+
val map = Arguments.createMap()
|
|
94
|
+
map.putBoolean("isVerified", verifyResponse!!.isVerified)
|
|
95
|
+
map.putString("token", verifyResponse.token)
|
|
96
|
+
map.putString("failureReason", verifyResponse.failureReason)
|
|
97
|
+
promise.resolve(map)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun launch(promise: Promise, fn: suspend (client: AuthsignalEmail) -> Unit) {
|
|
103
|
+
coroutineScope.launch {
|
|
104
|
+
authsignal?.let {
|
|
105
|
+
fn(it)
|
|
106
|
+
} ?: run {
|
|
107
|
+
Log.w("init_error", "AuthsignalEmailModule is not initialized.")
|
|
108
|
+
|
|
109
|
+
promise.resolve(null)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
package com.authsignal.react
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.ActivityNotFoundException
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import com.authsignal.TokenCache.Companion.shared
|
|
8
|
+
import com.authsignal.react.AuthenticationActivity.Companion.authenticateUsingBrowser
|
|
9
|
+
import com.facebook.react.bridge.ActivityEventListener
|
|
10
|
+
import com.facebook.react.bridge.Arguments
|
|
11
|
+
import com.facebook.react.bridge.Callback
|
|
12
|
+
import com.facebook.react.bridge.Promise
|
|
13
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
14
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
15
|
+
import com.facebook.react.bridge.ReactMethod
|
|
16
|
+
import java.net.URLDecoder
|
|
17
|
+
|
|
18
|
+
class AuthsignalModule(private val reactContext: ReactApplicationContext) :
|
|
19
|
+
ReactContextBaseJavaModule(
|
|
20
|
+
reactContext
|
|
21
|
+
), ActivityEventListener {
|
|
22
|
+
private var callback: Callback? = null
|
|
23
|
+
|
|
24
|
+
init {
|
|
25
|
+
reactContext.addActivityEventListener(this)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun getConstants(): Map<String, Any>? {
|
|
29
|
+
val constants: MutableMap<String, Any> = HashMap()
|
|
30
|
+
constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
|
|
31
|
+
return constants
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override fun getName(): String {
|
|
35
|
+
return "AuthsignalModule"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@ReactMethod
|
|
39
|
+
fun setToken(token: String?, promise: Promise) {
|
|
40
|
+
shared.token = token
|
|
41
|
+
|
|
42
|
+
promise.resolve("token_set")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@ReactMethod
|
|
46
|
+
fun launch(url: String?, callback: Callback) {
|
|
47
|
+
val activity = currentActivity
|
|
48
|
+
val parsedUrl = Uri.parse(url)
|
|
49
|
+
this.callback = callback
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
if (activity != null) {
|
|
53
|
+
authenticateUsingBrowser(activity, parsedUrl)
|
|
54
|
+
} else {
|
|
55
|
+
val error = Arguments.createMap()
|
|
56
|
+
error.putString("error", "activity_not_available")
|
|
57
|
+
error.putString("error_description", "Android Activity is null.")
|
|
58
|
+
callback.invoke(error)
|
|
59
|
+
}
|
|
60
|
+
} catch (e: ActivityNotFoundException) {
|
|
61
|
+
val error = Arguments.createMap()
|
|
62
|
+
error.putString("error", "browser_not_available")
|
|
63
|
+
error.putString("error_description", "No browser app is installed")
|
|
64
|
+
callback.invoke(error)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override fun onActivityResult(
|
|
69
|
+
activity: Activity,
|
|
70
|
+
requestCode: Int,
|
|
71
|
+
resultCode: Int,
|
|
72
|
+
data: Intent?
|
|
73
|
+
) {
|
|
74
|
+
val cb = this@AuthsignalModule.callback ?: return
|
|
75
|
+
|
|
76
|
+
val hasResult =
|
|
77
|
+
resultCode == Activity.RESULT_OK && requestCode == AuthenticationActivity.AUTHENTICATION_REQUEST && data!!.data != null
|
|
78
|
+
|
|
79
|
+
if (hasResult) {
|
|
80
|
+
try {
|
|
81
|
+
val redirectUrl = data!!.data.toString()
|
|
82
|
+
val query = redirectUrl.split("[?]".toRegex()).dropLastWhile { it.isEmpty() }
|
|
83
|
+
.toTypedArray()[1]
|
|
84
|
+
val pairs = query.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
85
|
+
var token: String? = null
|
|
86
|
+
for (pair in pairs) {
|
|
87
|
+
val index = pair.indexOf("=")
|
|
88
|
+
val name = URLDecoder.decode(pair.substring(0, index), "UTF-8")
|
|
89
|
+
val value = URLDecoder.decode(pair.substring(index + 1), "UTF-8")
|
|
90
|
+
if (name == "token") {
|
|
91
|
+
token = value
|
|
92
|
+
|
|
93
|
+
shared.token = value
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
cb.invoke(null, token)
|
|
97
|
+
} catch (ex: Exception) {
|
|
98
|
+
val error = Arguments.createMap()
|
|
99
|
+
error.putString("error", "malformed_url")
|
|
100
|
+
error.putString("error_description", "Malformed redirect url")
|
|
101
|
+
cb.invoke(error)
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
val error = Arguments.createMap()
|
|
105
|
+
error.putString("error", "user_cancelled")
|
|
106
|
+
error.putString("error_description", "User cancelled")
|
|
107
|
+
cb.invoke(error)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this@AuthsignalModule.callback = null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
override fun onNewIntent(intent: Intent) {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package com.authsignal.react
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class AuthsignalPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf<NativeModule>(
|
|
11
|
+
AuthsignalModule(reactContext),
|
|
12
|
+
AuthsignalEmailModule(reactContext),
|
|
13
|
+
AuthsignalPasskeyModule(reactContext),
|
|
14
|
+
AuthsignalPushModule(reactContext),
|
|
15
|
+
AuthsignalSMSModule(reactContext),
|
|
16
|
+
AuthsignalTOTPModule(reactContext)
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
21
|
+
return emptyList()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
package com.authsignal.react
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.authsignal.passkey.AuthsignalPasskey
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.Promise
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
9
|
+
import com.facebook.react.bridge.ReactMethod
|
|
10
|
+
import kotlinx.coroutines.CoroutineScope
|
|
11
|
+
import kotlinx.coroutines.Dispatchers
|
|
12
|
+
import kotlinx.coroutines.SupervisorJob
|
|
13
|
+
import kotlinx.coroutines.launch
|
|
14
|
+
|
|
15
|
+
class AuthsignalPasskeyModule(private val reactContext: ReactApplicationContext) :
|
|
16
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
17
|
+
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
|
18
|
+
private var authsignal: AuthsignalPasskey? = null
|
|
19
|
+
private var defaultError = "unexpected_error"
|
|
20
|
+
|
|
21
|
+
override fun getConstants(): Map<String, Any>? {
|
|
22
|
+
val constants: MutableMap<String, Any> = HashMap()
|
|
23
|
+
constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
|
|
24
|
+
return constants
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override fun getName(): String {
|
|
28
|
+
return "AuthsignalPasskeyModule"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactMethod
|
|
32
|
+
fun initialize(tenantID: String, baseURL: String, promise: Promise) {
|
|
33
|
+
val activity = reactContext.currentActivity
|
|
34
|
+
|
|
35
|
+
if (activity != null) {
|
|
36
|
+
authsignal = AuthsignalPasskey(tenantID, baseURL, activity)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
promise.resolve(null)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@ReactMethod
|
|
43
|
+
fun signUp(token: String?, username: String?, displayName: String?, promise: Promise) {
|
|
44
|
+
launch(promise) {
|
|
45
|
+
val response = it.signUp(token, username, displayName)
|
|
46
|
+
|
|
47
|
+
if (response.error != null) {
|
|
48
|
+
val errorCode = response.errorType ?: defaultError
|
|
49
|
+
|
|
50
|
+
promise.reject(errorCode, response.error)
|
|
51
|
+
} else {
|
|
52
|
+
val signUpResponse = response.data
|
|
53
|
+
val map = Arguments.createMap()
|
|
54
|
+
map.putString("token", signUpResponse!!.token)
|
|
55
|
+
promise.resolve(map)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@ReactMethod
|
|
61
|
+
fun signIn(action: String?, token: String?, promise: Promise) {
|
|
62
|
+
launch(promise) {
|
|
63
|
+
val response = it.signIn(action, token)
|
|
64
|
+
|
|
65
|
+
if (response.error != null) {
|
|
66
|
+
val errorCode = response.errorType ?: defaultError
|
|
67
|
+
|
|
68
|
+
promise.reject(errorCode, response.error)
|
|
69
|
+
} else {
|
|
70
|
+
val signInResponse = response.data
|
|
71
|
+
val map = Arguments.createMap()
|
|
72
|
+
map.putBoolean("isVerified", signInResponse!!.isVerified)
|
|
73
|
+
map.putString("token", signInResponse.token)
|
|
74
|
+
map.putString("userId", signInResponse.userId)
|
|
75
|
+
map.putString("userAuthenticatorId", signInResponse.userAuthenticatorId)
|
|
76
|
+
map.putString("username", signInResponse.username)
|
|
77
|
+
map.putString("displayName", signInResponse.displayName)
|
|
78
|
+
promise.resolve(map)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@ReactMethod
|
|
84
|
+
fun isAvailableOnDevice(promise: Promise) {
|
|
85
|
+
launch(promise) {
|
|
86
|
+
val response = it.isAvailableOnDevice()
|
|
87
|
+
|
|
88
|
+
promise.resolve(response.data ?: false)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private fun launch(promise: Promise, fn: suspend (client: AuthsignalPasskey) -> Unit) {
|
|
93
|
+
coroutineScope.launch {
|
|
94
|
+
authsignal?.let {
|
|
95
|
+
fn(it)
|
|
96
|
+
} ?: run {
|
|
97
|
+
Log.w("init_error", "AuthsignalTOTPModule is not initialized.")
|
|
98
|
+
|
|
99
|
+
promise.resolve(null)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|