diff --git a/ios/StatusKeycard.m b/ios/StatusKeycard.m index 31fc445..0a20b62 100644 --- a/ios/StatusKeycard.m +++ b/ios/StatusKeycard.m @@ -4,5 +4,7 @@ RCT_EXTERN_METHOD(nfcIsSupported:(RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(openNfcSettings:(RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(signPinless:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) + @end diff --git a/ios/StatusKeycard.swift b/ios/StatusKeycard.swift index fc8c416..2c5f402 100644 --- a/ios/StatusKeycard.swift +++ b/ios/StatusKeycard.swift @@ -12,18 +12,18 @@ class StatusKeycard: NSObject { if #available(iOS 13.0, *) { keycardController = KeycardController(onConnect: { [unowned self] channel in do { - let cmdSet = KeycardCommandSet(cardChannel: channel) - let info = try ApplicationInfo(cmdSet.select().checkOK().data) - print(info) - self.keycardController?.stop(alertMessage: "Success") + let cmdSet = KeycardCommandSet(cardChannel: channel) + let info = try ApplicationInfo(cmdSet.select().checkOK().data) + print(info) + self.keycardController?.stop(alertMessage: "Success") } catch { - print("Error: \(error)") - self.keycardController?.stop(errorMessage: "Read error. Please try again.") + print("Error: \(error)") + self.keycardController?.stop(errorMessage: "Read error. Please try again.") } - self.keycardController = nil + self.keycardController = nil }, onFailure: { [unowned self] error in - print("Disconnected: \(error)") - self.keycardController = nil + print("Disconnected: \(error)") + self.keycardController = nil }) keycardController?.start(alertMessage: "Hold your iPhone near a Status Keycard.") } else { @@ -36,6 +36,46 @@ class StatusKeycard: NSObject { reject("E_KEYCARD", "Unsupported on iOS", nil) } + @objc + func signPinless(_ hash: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + if #available(iOS 13.0, *) { + DispatchQueue.main.async { + self.keycardController = KeycardController(onConnect: { [unowned self] channel in + do { + let cmdSet = CashCommandSet(cardChannel: channel) + let info = try CashApplicationInfo(cmdSet.select().checkOK().data) + print("SELECT") + print(info) + + let message = self.hexToBytes(hash) + let res = try cmdSet.sign(data: message).checkOK() + print("SELECT") + print(res) + + self.keycardController?.stop(alertMessage: "SELECT: Success") + print("DONE!") + resolve(res.data.toHexString()) + } catch { + reject("E_KEYCARD", "error", nil) + print("Error: \(error)") + self.keycardController?.stop(errorMessage: "Read error. Please try again.") + } + self.keycardController = nil + }, onFailure: { [unowned self] error in + reject("E_KEYCARD", "disconnected", nil) + print("Disconnected: \(error)") + self.keycardController = nil + }) + self.keycardController?.start(alertMessage: "Hold your iPhone near a Status Keycard.") + } + } else { + print("Unavailable") + reject("E_KEYCARD", "unavailable", nil) + } + } + + + @objc func nfcIsSupported(_ resolve: RCTPromiseResolveBlock, rejecter _: RCTPromiseRejectBlock) -> Void { if #available(iOS 13.0, *) { @@ -49,4 +89,20 @@ class StatusKeycard: NSObject { static func requiresMainQueueSetup() -> Bool { return true } + + func hexToBytes(_ hex: String) -> [UInt8] { + var last = hex.first + return hex.dropFirst().compactMap { + guard + let lastHexDigitValue = last?.hexDigitValue, + let hexDigitValue = $0.hexDigitValue else { + last = $0 + return nil + } + defer { + last = nil + } + return UInt8(lastHexDigitValue * 16 + hexDigitValue) + } + } }