//Copyright (c) 2019 Facebook. All rights reserved. import Foundation import CYBAVOWallet @objc(RNAuth) class RNAuth: NSObject { var domain = Bundle.main.bundleIdentifier ?? "" override init() { super.init() Auth.shared.addSignInStateDelegate(self) } @objc func signIn(_ token: String, withIdentityProvider identityProvider: String, withExtras extras: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { var e = [String:String]() for (key, value) in extras { if let key = key as? String, let value = value as? String { e[key] = value } } Auth.shared.signIn(token: token, identityProvider: identityProvider, extras: e){ result in switch(result) { case .success(let e): print("signin success \(e)") let dict = RNWalletSDK.toDict(e) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func signUp(_ token: String, withIdentityProvider identityProvider: String, withExtras extras: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ var e = [String:String]() for (key, value) in extras { if let key = key as? String, let value = value as? String { e[key] = value } } Auth.shared.signUp(token: token, identityProvider: identityProvider, extras: e){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func signOut(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ Auth.shared.signOut() resolve(0) } @objc public func getSignInState(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { var state: RNSignInState switch Auth.shared.getSignInState() { case .SignedIn: state = .SIGNED_IN case .SignedOut: state = .SIGNED_OUT case .SessionExpired: state = .SESSION_EXPIRED case .SessionInvalid: state = .SESSION_INVALID case .Unknown: state = .UNKNOWN case .needVerifyOtp: state = .SIGNED_IN case .needRegisterPhone: state = .SIGNED_IN @unknown default: state = .UNKNOWN } resolve(state.rawValue) } @objc public func getUserState(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ Auth.shared.getUserState(){ result in switch(result) { case .success(let data): let user = RNWalletSDK.toDict(data) resolve(user) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func setupPinCode(_ pinCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ Auth.shared.setupPinCode(pinCode: pinCode) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func setupPinCodeWithPinSecret(_ byPinSecret: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ guard let pinSecret = PinSecretBridge.fromDictionary(dict: byPinSecret) else{ reject("0", "PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } Auth.shared.setupPinCode(pinSecret: pinSecret) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func setupBackupChallenge(_ pinCode: String, withChallenge1 challenge1: NSDictionary, withChallenge2 challenge2: NSDictionary, withChallenge3 challenge3: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ do { guard let q1 = challenge1["question"] as? String, let q2 = challenge2["question"] as? String, let q3 = challenge3["question"] as? String, let a1 = challenge1["answer"] as? String, let a2 = challenge2["answer"] as? String, let a3 = challenge3["answer"] as? String else { reject("0", "invalid question/answer pairs", NSError(domain: "", code: 0, userInfo: nil)) return } let c1 = try BackupChallenge(question: q1, answer: a1) let c2 = try BackupChallenge(question: q2, answer: a2) let c3 = try BackupChallenge(question: q3, answer: a3) Auth.shared.setupBackupChallenge(pinCode: pinCode, challenge1: c1, challenge2: c2, challenge3: c3){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } catch(let error) { reject("0", error.localizedDescription, error) } } @objc public func setupBackupChallengeWithPinSecret(_ byPinSecret: NSDictionary, withChallenge1 challenge1: NSDictionary, withChallenge2 challenge2: NSDictionary, withChallenge3 challenge3: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ do { guard let q1 = challenge1["question"] as? String, let q2 = challenge2["question"] as? String, let q3 = challenge3["question"] as? String, let a1 = challenge1["answer"] as? String, let a2 = challenge2["answer"] as? String, let a3 = challenge3["answer"] as? String else { reject("0", "invalid question/answer pairs", NSError(domain: "", code: 0, userInfo: nil)) return } guard let pinSecret = PinSecretBridge.fromDictionary(dict: byPinSecret) else{ reject("0", "PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } let c1 = try BackupChallenge(question: q1, answer: a1) let c2 = try BackupChallenge(question: q2, answer: a2) let c3 = try BackupChallenge(question: q3, answer: a3) Auth.shared.setupBackupChallenge(pinSecret: pinSecret, challenge1: c1, challenge2: c2, challenge3: c3){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } catch(let error) { reject("0", error.localizedDescription, error) } } @objc public func restorePinCode(_ pinCode: String, withChallenge1 challenge1: NSDictionary, withChallenge2 challenge2: NSDictionary, withChallenge3 challenge3: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ do { guard let q1 = challenge1["question"] as? String, let q2 = challenge2["question"] as? String, let q3 = challenge3["question"] as? String, let a1 = challenge1["answer"] as? String, let a2 = challenge2["answer"] as? String, let a3 = challenge3["answer"] as? String else { reject("0", "invalid question/answer pairs", NSError(domain: "", code: 0, userInfo: nil)) return } let c1 = try BackupChallenge(question: q1, answer: a1) let c2 = try BackupChallenge(question: q2, answer: a2) let c3 = try BackupChallenge(question: q3, answer: a3) Auth.shared.restorePinCode(pinCode: pinCode, challenge1: c1, challenge2: c2, challenge3: c3){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } catch(let error) { reject("0", error.localizedDescription, error) } } @objc public func restorePinCodeWithPinSecret(_ byPinSecret: NSDictionary, withChallenge1 challenge1: NSDictionary, withChallenge2 challenge2: NSDictionary, withChallenge3 challenge3: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ do { guard let q1 = challenge1["question"] as? String, let q2 = challenge2["question"] as? String, let q3 = challenge3["question"] as? String, let a1 = challenge1["answer"] as? String, let a2 = challenge2["answer"] as? String, let a3 = challenge3["answer"] as? String else { reject("0", "invalid question/answer pairs", NSError(domain: "", code: 0, userInfo: nil)) return } guard let pinSecret = PinSecretBridge.fromDictionary(dict: byPinSecret) else{ reject("0", "PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } let c1 = try BackupChallenge(question: q1, answer: a1) let c2 = try BackupChallenge(question: q2, answer: a2) let c3 = try BackupChallenge(question: q3, answer: a3) Auth.shared.restorePinCode(pinSecret: pinSecret, challenge1: c1, challenge2: c2, challenge3: c3){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } catch(let error) { reject("0", error.localizedDescription, error) } } @objc public func changePinCode(_ newPinCode: String, current currentPinCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ Auth.shared.changePinCode(newPinCode: newPinCode, currentPinCode: currentPinCode){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func changePinCodeWithPinSecret(_ byNewPinSecret: NSDictionary, byCurrentPinSecret: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ guard let newPinSecret = PinSecretBridge.fromDictionary(dict: byNewPinSecret) else{ reject("0", "new PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } guard let currentPinSecret = PinSecretBridge.fromDictionary(dict: byCurrentPinSecret) else{ reject("0", "current PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } Auth.shared.changePinCode(newPinSecret: newPinSecret, currentPinSecret: currentPinSecret){ result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func getRestoreQuestions(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Auth.shared.getRestoreQuestions(){ result in switch(result) { case .success(let data): if data.questions.count < 3 { reject("0", "invalid parameter", NSError(domain: "", code: 0, userInfo: nil)) return } let questions: [String: Any] = [ "question1": data.questions[0], "question2": data.questions[1], "question3": data.questions[2] ] resolve(questions) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func verifyRestoreQuestions(_ challenge1: NSDictionary, withChallenge2 challenge2: NSDictionary, withChallenge3 challenge3: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ do { guard let q1 = challenge1["question"] as? String, let q2 = challenge2["question"] as? String, let q3 = challenge3["question"] as? String, let a1 = challenge1["answer"] as? String, let a2 = challenge2["answer"] as? String, let a3 = challenge3["answer"] as? String else { reject("0", "invalid question/answer pairs", NSError(domain: "", code: 0, userInfo: nil)) return } let c1 = try BackupChallenge(question: q1, answer: a1) let c2 = try BackupChallenge(question: q2, answer: a2) let c3 = try BackupChallenge(question: q3, answer: a3) Auth.shared.verifyRestoreQuestions(challenge1: c1, challenge2: c2, challenge3: c3) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } catch(let error) { reject("0", error.localizedDescription, error) } } @objc public func forgotPinCode(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ Auth.shared.forgotPinCode() { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func verifyRecoveryCode(_ recoveryCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock){ print("verifyRecoveryCode \(recoveryCode)") Auth.shared.verifyRecoveryCode(recoveryCode: recoveryCode) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) print("verifyRecoveryCode dict \(recoveryCode)") resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func recoverPinCode(_ pinCode: String, withCode recoveryCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Auth.shared.recoverPinCode(pinCode: pinCode, recoveryCode: recoveryCode) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func recoverPinCodeWithPinSecret(_ byPinSecret: NSDictionary, withCode recoveryCode: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { guard let pinSecret = PinSecretBridge.fromDictionary(dict: byPinSecret) else{ reject("0", "PinSecret not found", NSError(domain: "", code: 0, userInfo: nil)) return } Auth.shared.recoverPinCode(pinSecret: pinSecret, recoveryCode: recoveryCode) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func setPushDeviceToken(_ pushDeviceToken: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Auth.shared.setPushDeviceToken(deviceToken: pushDeviceToken) { result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func registerPhoneNumber(_ countryCode: String, phone: String, duration: NSInteger, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Auth.shared.registerPhoneNumber(contryCode: countryCode, phone: phone, duration: Int64(duration)){result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } @objc public func verifyOtp(_ actionToken: String, code: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { Auth.shared.verifyOtp(actionToken: actionToken, code: code){result in switch(result) { case .success(let data): let dict = RNWalletSDK.toDict(data) resolve(dict) case .failure(let error): let errorCode = error.code.rawValue do{ let e = NSError(domain: try String(error.message), code: errorCode, userInfo: nil) reject(String(error.code.rawValue), error.message, e) }catch{ let e = NSError(domain: "failed to get error.message", code: errorCode, userInfo: nil) reject(String(errorCode), "failed to get error.message", e) } } } } } extension RNAuth : SignInStateDelegate { func onUserStateChanged(state: SignInState) { var newState: RNSignInState switch state { case .SignedIn: newState = .SIGNED_IN case .SignedOut: newState = .SIGNED_OUT case .SessionExpired: newState = .SESSION_EXPIRED case .SessionInvalid: newState = .SESSION_INVALID case .Unknown: newState = .UNKNOWN case .needVerifyOtp: newState = .SIGNED_IN EventEmitter.sharedInstance.dispatch(name: "onSignInStateChanged", body: RNSignInState.NEED_VERIFY_OTP.rawValue) return case .needRegisterPhone: EventEmitter.sharedInstance.dispatch(name: "onSignInStateChanged", body: RNSignInState.NEED_REGISTER_PHONE.rawValue) newState = .SIGNED_IN return @unknown default: newState = .UNKNOWN } EventEmitter.sharedInstance.dispatch(name: "onSignInStateChanged", body: newState.rawValue) } } extension RNAuth { @objc func constantsToExport() -> [AnyHashable : Any]! { var constants = [AnyHashable : Any]() var signInState = [String : Any]() for state in RNSignInState.allCases { signInState[state.name] = state.rawValue } constants["SignInState"] = signInState let events: [AnyHashable : Any] = [ "onSignInStateChanged": "onSignInStateChanged", ] constants["Events"] = events return constants } @objc static func requiresMainQueueSetup() -> Bool { return true } }