diff --git a/android/src/main/java/com/authsignal/react/AuthsignalInAppModule.kt b/android/src/main/java/com/authsignal/react/AuthsignalInAppModule.kt index cdc031d..28bdb67 100644 --- a/android/src/main/java/com/authsignal/react/AuthsignalInAppModule.kt +++ b/android/src/main/java/com/authsignal/react/AuthsignalInAppModule.kt @@ -133,6 +133,74 @@ class AuthsignalInAppModule(private val reactContext: ReactApplicationContext) : } } + @ReactMethod + fun createPin(pin: String, username: String, token: String?, promise: Promise) { + launch(promise) { + val response = it.createPin( + pin = pin, + username = username, + token = token, + ) + + if (response.error != null) { + val errorCode = response.errorCode ?: defaultError + + promise.reject(errorCode, response.error) + } else { + promise.resolve(response.data) + } + } + } + + @ReactMethod + fun verifyPin(pin: String, username: String, action: String?, promise: Promise) { + launch(promise) { + val response = it.verifyPin( + pin = pin, + username = username, + action = action, + ) + + if (response.error != null) { + val errorCode = response.errorCode ?: defaultError + + promise.reject(errorCode, response.error) + } else { + promise.resolve(response.data) + } + } + } + + @ReactMethod + fun deletePin(username: String, promise: Promise) { + launch(promise) { + val response = it.deletePin(username = username) + + if (response.error != null) { + val errorCode = response.errorCode ?: defaultError + + promise.reject(errorCode, response.error) + } else { + promise.resolve(response.data) + } + } + } + + @ReactMethod + fun getAllUsernames(promise: Promise) { + launch(promise) { + val response = it.getAllUsernames() + + if (response.error != null) { + val errorCode = response.errorCode ?: defaultError + + promise.reject(errorCode, response.error) + } else { + promise.resolve(response.data) + } + } + } + private fun launch(promise: Promise, fn: suspend (client: AuthsignalInApp) -> Unit) { coroutineScope.launch { authsignal?.let { diff --git a/ios/Authsignal.xcodeproj/project.pbxproj b/ios/Authsignal.xcodeproj/project.pbxproj index 08562d9..6a66120 100644 --- a/ios/Authsignal.xcodeproj/project.pbxproj +++ b/ios/Authsignal.xcodeproj/project.pbxproj @@ -20,6 +20,10 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libAuthsignal.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAuthsignal.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D870279B2ECD0BA40097560C /* AuthsignalInAppModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalInAppModule.m; sourceTree = ""; }; + D870279C2ECD0BA40097560C /* AuthsignalInAppModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthsignalInAppModule.swift; sourceTree = ""; }; + D870279D2ECD0BA40097560C /* AuthsignalQRModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalQRModule.m; sourceTree = ""; }; + D870279E2ECD0BA40097560C /* AuthsignalQRModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthsignalQRModule.swift; sourceTree = ""; }; D8AE39E42C729A88003759EB /* AuthsignalEmailModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalEmailModule.m; sourceTree = ""; }; D8AE39E52C729A88003759EB /* AuthsignalSMSModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthsignalSMSModule.swift; sourceTree = ""; }; D8AE39E62C729A88003759EB /* AuthsignalTOTPModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalTOTPModule.m; sourceTree = ""; }; @@ -33,8 +37,6 @@ D8EC5CD52A4D1EE00085B442 /* AuthsignalPushModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalPushModule.m; sourceTree = ""; }; D8EC5CD62A4D1EE00085B442 /* AuthsignalPasskeyModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalPasskeyModule.m; sourceTree = ""; }; D8EC5CD72A4D1EE90085B442 /* Authsignal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Authsignal-Bridging-Header.h"; sourceTree = ""; }; - DDDCE5EE2DDD8E5B0095B3F2 /* AuthsignalDeviceModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalDeviceModule.m; sourceTree = ""; }; - DDDCE5EF2DDD8E5B0095B3F2 /* AuthsignalDeviceModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthsignalDeviceModule.swift; sourceTree = ""; }; DDDD1001AAAA1111BBBB2222 /* AuthsignalWhatsappModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthsignalWhatsappModule.m; sourceTree = ""; }; DDDD1002AAAA1111BBBB2222 /* AuthsignalWhatsappModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthsignalWhatsappModule.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -74,10 +76,12 @@ D8EC5CD32A4D1EE00085B442 /* AuthsignalPasskeyModule.swift */, D8EC5CD52A4D1EE00085B442 /* AuthsignalPushModule.m */, D8EC5CD42A4D1EE00085B442 /* AuthsignalPushModule.swift */, - DDDCE5EE2DDD8E5B0095B3F2 /* AuthsignalDeviceModule.m */, - DDDCE5EF2DDD8E5B0095B3F2 /* AuthsignalDeviceModule.swift */, DDDD1001AAAA1111BBBB2222 /* AuthsignalWhatsappModule.m */, DDDD1002AAAA1111BBBB2222 /* AuthsignalWhatsappModule.swift */, + D870279B2ECD0BA40097560C /* AuthsignalInAppModule.m */, + D870279C2ECD0BA40097560C /* AuthsignalInAppModule.swift */, + D870279D2ECD0BA40097560C /* AuthsignalQRModule.m */, + D870279E2ECD0BA40097560C /* AuthsignalQRModule.swift */, 134814211AA4EA7D00B7C361 /* Products */, ); sourceTree = ""; diff --git a/ios/AuthsignalInAppModule.m b/ios/AuthsignalInAppModule.m index 4c4e839..16ae375 100644 --- a/ios/AuthsignalInAppModule.m +++ b/ios/AuthsignalInAppModule.m @@ -28,4 +28,23 @@ @interface RCT_EXTERN_MODULE(AuthsignalInAppModule, NSObject) resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(createPin:(NSString)pin + withUsername:(NSString)username + withToken:(NSString)token + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(verifyPin:(NSString)pin + withUsername:(NSString)username + withAction:(NSString)action + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(deletePin:(NSString)username + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getAllUsernames:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + @end diff --git a/ios/AuthsignalInAppModule.swift b/ios/AuthsignalInAppModule.swift index 75a1de4..f9b068b 100644 --- a/ios/AuthsignalInAppModule.swift +++ b/ios/AuthsignalInAppModule.swift @@ -152,6 +152,111 @@ class AuthsignalInAppModule: NSObject { } } } + + @objc func createPin( + _ pin: NSString, + withUsername username: NSString, + withToken token: NSString?, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { + guard let authsignal = authsignal else { + resolve(nil) + return + } + + let pinStr = pin as String + let usernameStr = username as String + let tokenStr = token as String? + + Task.init { + let response = await authsignal.createPin( + pin: pinStr, + username: usernameStr, + token: tokenStr + ) + + if let error = response.error { + reject(response.errorCode ?? "unexpected_error", error, nil) + } else { + resolve(response.data) + } + } + } + + @objc func verifyPin( + _ pin: NSString, + withUsername username: NSString, + withAction action: NSString?, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { + guard let authsignal = authsignal else { + resolve(nil) + return + } + + let pinStr = pin as String + let usernameStr = username as String + let actionStr = action as String? + + Task.init { + let response = await authsignal.verifyPin( + pin: pinStr, + username: usernameStr, + action: actionStr + ) + + if let error = response.error { + reject(response.errorCode ?? "unexpected_error", error, nil) + } else { + resolve(response.data) + } + } + } + + @objc func deletePin( + _ username: NSString, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { + guard let authsignal = authsignal else { + resolve(nil) + return + } + + let usernameStr = username as String + + Task.init { + let response = await authsignal.deletePin(username: usernameStr) + + if let error = response.error { + reject(response.errorCode ?? "unexpected_error", error, nil) + } else { + resolve(response.data) + } + } + } + + @objc func getAllUsernames( + _ resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) -> Void { + guard let authsignal = authsignal else { + resolve(nil) + return + } + + Task.init { + let response = await authsignal.getAllUsernames() + + if let error = response.error { + reject(response.errorCode ?? "unexpected_error", error, nil) + } else { + resolve(response.data) + } + } + } func getKeychainAccess(value: String?) -> KeychainAccess { switch value { diff --git a/package.json b/package.json index f2f574a..a45eedb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-authsignal", - "version": "2.2.0", + "version": "2.2.1", "description": "The official Authsignal React Native library.", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/react-native-authsignal.podspec b/react-native-authsignal.podspec index 3291958..05fd2e0 100644 --- a/react-native-authsignal.podspec +++ b/react-native-authsignal.podspec @@ -17,7 +17,7 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency 'Authsignal', '2.2.1' + s.dependency 'Authsignal', '2.2.2' # Don't install the dependencies when we run `pod install` in the old architecture. if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then diff --git a/src/inapp.ts b/src/inapp.ts index aea5de4..daa0207 100644 --- a/src/inapp.ts +++ b/src/inapp.ts @@ -3,11 +3,14 @@ import { handleErrorCodes, LINKING_ERROR } from './error'; import type { AuthsignalResponse, AppCredential, - InAppVerifyRequest, + InAppVerifyInput, InAppVerifyResponse, InAppAddCredentialInput, InAppGetCredentialInput, InAppRemoveCredentialInput, + CreatePinInput, + VerifyPinInput, + VerifyPinResponse, } from './types'; interface ConstructorArgs { @@ -106,7 +109,7 @@ export class AuthsignalInApp { } } - async verify({ action, username }: InAppVerifyRequest = {}): Promise< + async verify({ action, username }: InAppVerifyInput = {}): Promise< AuthsignalResponse > { await this.ensureModuleIsInitialized(); @@ -124,6 +127,76 @@ export class AuthsignalInApp { } } + async createPin({ + pin, + username, + token, + }: CreatePinInput): Promise> { + await this.ensureModuleIsInitialized(); + + try { + const data = await AuthsignalInAppModule.createPin(pin, username, token); + return { data }; + } catch (ex) { + if (this.enableLogging) { + console.log(ex); + } + + return handleErrorCodes(ex); + } + } + + async verifyPin({ + pin, + username, + action, + }: VerifyPinInput): Promise> { + await this.ensureModuleIsInitialized(); + + try { + const data = await AuthsignalInAppModule.verifyPin(pin, username, action); + return { data }; + } catch (ex) { + if (this.enableLogging) { + console.log(ex); + } + + return handleErrorCodes(ex); + } + } + + async deletePin({ + username, + }: VerifyPinInput): Promise> { + await this.ensureModuleIsInitialized(); + + try { + const data = await AuthsignalInAppModule.deletePin(username); + return { data }; + } catch (ex) { + if (this.enableLogging) { + console.log(ex); + } + + return handleErrorCodes(ex); + } + } + + async getAllUsernames(): Promise> { + await this.ensureModuleIsInitialized(); + + try { + const data = await AuthsignalInAppModule.getAllUsernames(); + return { data }; + } catch (ex) { + if (this.enableLogging) { + console.log(ex); + } + + return handleErrorCodes(ex); + } + } + private async ensureModuleIsInitialized() { if (initialized) { return; diff --git a/src/types.ts b/src/types.ts index c4acc0d..2021b65 100644 --- a/src/types.ts +++ b/src/types.ts @@ -97,7 +97,7 @@ export interface InAppRemoveCredentialInput { username?: string; } -export interface InAppVerifyRequest { +export interface InAppVerifyInput { action?: string; username?: string; } @@ -109,6 +109,28 @@ export interface InAppVerifyResponse { username?: string; } +export interface CreatePinInput { + pin: string; + username: string; + token?: string; +} + +export interface VerifyPinInput { + pin: string; + username: string; + action?: string; +} + +export interface VerifyPinResponse { + isVerified: string; + token?: string; + userId?: string; +} + +export interface DeletePinInput { + username?: string; +} + export enum KeychainAccess { afterFirstUnlock = 'afterFirstUnlock', afterFirstUnlockThisDeviceOnly = 'afterFirstUnlockThisDeviceOnly',