Skip to content

Commit a0a8550

Browse files
authored
Add qr and inapp namespaces for app verification (#63)
1 parent 13143c1 commit a0a8550

17 files changed

+529
-247
lines changed

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,5 @@ dependencies {
7777

7878
implementation "androidx.browser:browser:1.2.0"
7979

80-
implementation("com.authsignal:authsignal-android:2.6.0")
80+
implementation("com.authsignal:authsignal-android:3.0.0-alpha")
8181
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.authsignal.react
2+
3+
import android.util.Log
4+
import com.authsignal.inapp.AuthsignalInApp
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 AuthsignalInAppModule(private val reactContext: ReactApplicationContext) :
16+
ReactContextBaseJavaModule(
17+
reactContext
18+
) {
19+
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
20+
private var authsignal: AuthsignalInApp? = null
21+
private var defaultError = "unexpected_error"
22+
23+
override fun getConstants(): Map<String, Any>? {
24+
val constants: MutableMap<String, Any> = HashMap()
25+
constants["bundleIdentifier"] = reactContext.applicationInfo.packageName
26+
return constants
27+
}
28+
29+
override fun getName(): String {
30+
return "AuthsignalInAppModule"
31+
}
32+
33+
@ReactMethod
34+
fun initialize(tenantID: String?, baseURL: String?, promise: Promise) {
35+
Log.d("AuthsignalInAppModule", "initialize: $tenantID, $baseURL")
36+
authsignal = AuthsignalInApp(tenantID!!, baseURL!!)
37+
38+
promise.resolve(null)
39+
}
40+
41+
@ReactMethod
42+
fun getCredential(promise: Promise) {
43+
launch(promise) {
44+
val response = it.getCredential()
45+
46+
if (response.error != null) {
47+
val errorCode = response.errorCode ?: defaultError
48+
49+
promise.reject(errorCode, response.error)
50+
} else if (response.data != null) {
51+
val credential = response.data
52+
val map = Arguments.createMap()
53+
map.putString("credentialId", credential!!.credentialId)
54+
map.putString("createdAt", credential.createdAt)
55+
map.putString("userId", credential.userId)
56+
map.putString("lastAuthenticatedAt", credential.lastAuthenticatedAt)
57+
promise.resolve(map)
58+
} else {
59+
promise.resolve(null)
60+
}
61+
}
62+
}
63+
64+
@ReactMethod
65+
fun addCredential(
66+
token: String?,
67+
promise: Promise
68+
) {
69+
launch(promise) {
70+
val response = it.addCredential(token, null)
71+
72+
if (response.error != null) {
73+
val errorCode = response.errorCode ?: defaultError
74+
75+
promise.reject(errorCode, response.error)
76+
} else {
77+
val credential = response.data
78+
val map = Arguments.createMap()
79+
map.putString("credentialId", credential!!.credentialId)
80+
map.putString("createdAt", credential.createdAt)
81+
map.putString("userId", credential.userId)
82+
map.putString("lastAuthenticatedAt", credential.lastAuthenticatedAt)
83+
promise.resolve(map)
84+
}
85+
}
86+
}
87+
88+
@ReactMethod
89+
fun removeCredential(promise: Promise) {
90+
launch(promise) {
91+
val response = it.removeCredential()
92+
93+
if (response.error != null) {
94+
val errorCode = response.errorCode ?: defaultError
95+
96+
promise.reject(errorCode, response.error)
97+
} else {
98+
promise.resolve(response.data)
99+
}
100+
}
101+
}
102+
103+
@ReactMethod
104+
fun verify(promise: Promise) {
105+
launch(promise) {
106+
val response = it.verify()
107+
108+
if (response.error != null) {
109+
val errorCode = response.errorCode ?: defaultError
110+
111+
promise.reject(errorCode, response.error)
112+
} else {
113+
val data = response.data!!
114+
val map = Arguments.createMap()
115+
map.putString("token", data.token)
116+
map.putString("userId", data.userId)
117+
map.putString("userAuthenticatorId", data.userAuthenticatorId)
118+
map.putString("username", data.username)
119+
promise.resolve(map)
120+
}
121+
}
122+
}
123+
124+
private fun launch(promise: Promise, fn: suspend (client: AuthsignalDevice) -> Unit) {
125+
coroutineScope.launch {
126+
authsignal?.let {
127+
fn(it)
128+
} ?: run {
129+
Log.w("init_error", "AuthsignalInAppModule is not initialized.")
130+
131+
promise.resolve(null)
132+
}
133+
}
134+
}
135+
}

android/src/main/java/com/authsignal/react/AuthsignalPackage.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ class AuthsignalPackage : ReactPackage {
1212
AuthsignalEmailModule(reactContext),
1313
AuthsignalPasskeyModule(reactContext),
1414
AuthsignalPushModule(reactContext),
15-
AuthsignalDeviceModule(reactContext),
15+
AuthsignalInAppModule(reactContext),
16+
AuthsignalQRCodeModule(reactContext),
1617
AuthsignalSMSModule(reactContext),
1718
AuthsignalTOTPModule(reactContext),
1819
AuthsignalWhatsappModule(reactContext)

android/src/main/java/com/authsignal/react/AuthsignalPushModule.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class AuthsignalPushModule(private val reactContext: ReactApplicationContext) :
5151
val map = Arguments.createMap()
5252
map.putString("credentialId", credential!!.credentialId)
5353
map.putString("createdAt", credential.createdAt)
54+
map.putString("userId", credential.userId)
5455
map.putString("lastAuthenticatedAt", credential.lastAuthenticatedAt)
5556
promise.resolve(map)
5657
}
@@ -70,7 +71,13 @@ class AuthsignalPushModule(private val reactContext: ReactApplicationContext) :
7071

7172
promise.reject(errorCode, response.error)
7273
} else {
73-
promise.resolve(response.data)
74+
val credential = response.data
75+
val map = Arguments.createMap()
76+
map.putString("credentialId", credential!!.credentialId)
77+
map.putString("createdAt", credential.createdAt)
78+
map.putString("userId", credential.userId)
79+
map.putString("lastAuthenticatedAt", credential.lastAuthenticatedAt)
80+
promise.resolve(map)
7481
}
7582
}
7683
}

android/src/main/java/com/authsignal/react/AuthsignalDeviceModule.kt renamed to android/src/main/java/com/authsignal/react/AuthsignalQRCodeModule.kt

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.authsignal.react
22

33
import android.util.Log
4-
import com.authsignal.device.AuthsignalDevice
4+
import com.authsignal.qr.AuthsignalQRCode
55
import com.facebook.react.bridge.Arguments
66
import com.facebook.react.bridge.Promise
77
import com.facebook.react.bridge.ReactApplicationContext
@@ -12,12 +12,12 @@ import kotlinx.coroutines.Dispatchers
1212
import kotlinx.coroutines.SupervisorJob
1313
import kotlinx.coroutines.launch
1414

15-
class AuthsignalDeviceModule(private val reactContext: ReactApplicationContext) :
15+
class AuthsignalQRCodeModule(private val reactContext: ReactApplicationContext) :
1616
ReactContextBaseJavaModule(
1717
reactContext
1818
) {
1919
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
20-
private var authsignal: AuthsignalDevice? = null
20+
private var authsignal: AuthsignalQRCode? = null
2121
private var defaultError = "unexpected_error"
2222

2323
override fun getConstants(): Map<String, Any>? {
@@ -27,12 +27,12 @@ class AuthsignalDeviceModule(private val reactContext: ReactApplicationContext)
2727
}
2828

2929
override fun getName(): String {
30-
return "AuthsignalDeviceModule"
30+
return "AuthsignalQRCodeModule"
3131
}
3232

3333
@ReactMethod
3434
fun initialize(tenantID: String?, baseURL: String?, promise: Promise) {
35-
Log.d("AuthsignalDeviceModule", "initialize: $tenantID, $baseURL")
35+
Log.d("AuthsignalQRCodeModule", "initialize: $tenantID, $baseURL")
3636
authsignal = AuthsignalDevice(tenantID!!, baseURL!!)
3737

3838
promise.resolve(null)
@@ -100,34 +100,6 @@ class AuthsignalDeviceModule(private val reactContext: ReactApplicationContext)
100100
}
101101
}
102102

103-
@ReactMethod
104-
fun getChallenge(promise: Promise) {
105-
launch(promise) {
106-
val response = it.getChallenge()
107-
108-
if (response.error != null) {
109-
val errorCode = response.errorCode ?: defaultError
110-
111-
promise.reject(errorCode, response.error)
112-
} else {
113-
val challenge = response.data
114-
115-
if (challenge == null) {
116-
promise.resolve(null)
117-
} else {
118-
val map = Arguments.createMap()
119-
map.putString("challengeId", challenge.challengeId)
120-
map.putString("actionCode", challenge.actionCode)
121-
map.putString("idempotencyKey", challenge.idempotencyKey)
122-
map.putString("ipAddress", challenge.ipAddress)
123-
map.putString("deviceId", challenge.deviceId)
124-
map.putString("userAgent", challenge.userAgent)
125-
promise.resolve(map)
126-
}
127-
}
128-
}
129-
}
130-
131103
@ReactMethod
132104
fun claimChallenge(
133105
challengeId: String,
@@ -175,33 +147,12 @@ class AuthsignalDeviceModule(private val reactContext: ReactApplicationContext)
175147
}
176148
}
177149

178-
@ReactMethod
179-
fun verify(promise: Promise) {
180-
launch(promise) {
181-
val response = it.verify()
182-
183-
if (response.error != null) {
184-
val errorCode = response.errorCode ?: defaultError
185-
186-
promise.reject(errorCode, response.error)
187-
} else {
188-
val data = response.data!!
189-
val map = Arguments.createMap()
190-
map.putString("token", data.token)
191-
map.putString("userId", data.userId)
192-
map.putString("userAuthenticatorId", data.userAuthenticatorId)
193-
map.putString("username", data.username)
194-
promise.resolve(map)
195-
}
196-
}
197-
}
198-
199150
private fun launch(promise: Promise, fn: suspend (client: AuthsignalDevice) -> Unit) {
200151
coroutineScope.launch {
201152
authsignal?.let {
202153
fn(it)
203154
} ?: run {
204-
Log.w("init_error", "AuthsignalDeviceModule is not initialized.")
155+
Log.w("init_error", "AuthsignalQRCodeModule is not initialized.")
205156

206157
promise.resolve(null)
207158
}

ios/AuthsignalInAppModule.m

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#import <React/RCTBridgeModule.h>
2+
#import <Foundation/Foundation.h>
3+
4+
@interface RCT_EXTERN_MODULE(AuthsignalInAppModule, NSObject)
5+
6+
RCT_EXTERN_METHOD(initialize:(NSString)tenantID
7+
withBaseURL:(NSString)baseURL
8+
resolver:(RCTPromiseResolveBlock)resolve
9+
rejecter:(RCTPromiseRejectBlock)reject)
10+
11+
RCT_EXTERN_METHOD(getCredential:(RCTPromiseResolveBlock)resolve
12+
rejecter:(RCTPromiseRejectBlock)reject)
13+
14+
RCT_EXTERN_METHOD(addCredential:(NSString)token
15+
withRequireUserAuthentication:(BOOL)requireUserAuthentication
16+
withKeychainAccess:(NSString)keychainAccess
17+
resolver:(RCTPromiseResolveBlock)resolve
18+
rejecter:(RCTPromiseRejectBlock)reject)
19+
20+
RCT_EXTERN_METHOD(removeCredential:(RCTPromiseResolveBlock)resolve
21+
rejecter:(RCTPromiseRejectBlock)reject)
22+
23+
RCT_EXTERN_METHOD(verify:(RCTPromiseResolveBlock)resolve
24+
rejecter:(RCTPromiseRejectBlock)reject)
25+
26+
@end

0 commit comments

Comments
 (0)