diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 0dce2bb7..54600bf7 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -73,6 +73,7 @@ PODS: - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) + - GzipSwift (5.1.1) - hermes-engine (0.70.6) - libevent (2.1.12) - OpenSSL-Universal (1.1.1100) @@ -303,6 +304,7 @@ PODS: - React-logger (0.70.6): - glog - react-native-openid4vp-ble (0.1.0): + - GzipSwift - React-Core - React-perflogger (0.70.6) - React-RCTActionSheet (0.70.6): @@ -450,6 +452,7 @@ SPEC REPOS: - Flipper-RSocket - FlipperKit - fmt + - GzipSwift - libevent - OpenSSL-Universal - SocketRocket @@ -544,6 +547,7 @@ SPEC CHECKSUMS: FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c @@ -562,7 +566,7 @@ SPEC CHECKSUMS: React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0 - react-native-openid4vp-ble: 18282d8ac2050613523bd85289ca47753afac0f4 + react-native-openid4vp-ble: 8ee0f01a69c757238f97c7cc613ddd024a7e4cee React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595 React-RCTActionSheet: 7316773acabb374642b926c19aef1c115df5c466 React-RCTAnimation: 5341e288375451297057391227f691d9b2326c3d diff --git a/ios/Openid4vpBle.xcodeproj/project.pbxproj b/ios/Openid4vpBle.xcodeproj/project.pbxproj index c45fc192..05b50f21 100644 --- a/ios/Openid4vpBle.xcodeproj/project.pbxproj +++ b/ios/Openid4vpBle.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 8D31C3FC2956B20F0073B710 /* WalletCryptoBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D31C3FB2956B20F0073B710 /* WalletCryptoBox.swift */; }; 8D31C3FE2956B2650073B710 /* WalletCryptoBoxBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D31C3FD2956B2650073B710 /* WalletCryptoBoxBuilder.swift */; }; 8D31C4022956B3EF0073B710 /* WalletCryptoBoxImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D31C4012956B3EF0073B710 /* WalletCryptoBoxImpl.swift */; }; + E223F0322977BE090042F919 /* TransferHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E223F0312977BE090042F919 /* TransferHandler.swift */; }; + E25800A42976BF8700968EA0 /* chunker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25800A32976BF8700968EA0 /* chunker.swift */; }; E2F1AFCB297176C200AC3355 /* BLEConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F1AFCA297176C200AC3355 /* BLEConstants.swift */; }; E2F1AFCD2971883500AC3355 /* WalletViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F1AFCC2971883500AC3355 /* WalletViewModel.swift */; }; F4FF95D7245B92E800C19C63 /* Openid4vpBle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Openid4vpBle.swift */; }; @@ -72,6 +74,8 @@ 8D31C3FD2956B2650073B710 /* WalletCryptoBoxBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletCryptoBoxBuilder.swift; sourceTree = ""; }; 8D31C4012956B3EF0073B710 /* WalletCryptoBoxImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletCryptoBoxImpl.swift; sourceTree = ""; }; B3E7B5891CC2AC0600A0062D /* Openid4vpBle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Openid4vpBle.m; sourceTree = ""; }; + E223F0312977BE090042F919 /* TransferHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferHandler.swift; sourceTree = ""; }; + E25800A32976BF8700968EA0 /* chunker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = chunker.swift; sourceTree = ""; }; E2F1AFCA297176C200AC3355 /* BLEConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEConstants.swift; sourceTree = ""; }; E2F1AFCC2971883500AC3355 /* WalletViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletViewModel.swift; sourceTree = ""; }; F4FF95D5245B92E700C19C63 /* Openid4vpBle-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Openid4vpBle-Bridging-Header.h"; sourceTree = ""; }; @@ -233,6 +237,8 @@ isa = PBXGroup; children = ( E2F1AFCA297176C200AC3355 /* BLEConstants.swift */, + E25800A32976BF8700968EA0 /* chunker.swift */, + E223F0312977BE090042F919 /* TransferHandler.swift */, ); path = Utility; sourceTree = ""; @@ -302,6 +308,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E223F0322977BE090042F919 /* TransferHandler.swift in Sources */, 8D069F752968305B00AB61A9 /* EventEmitter.swift in Sources */, 8D31C3F82956B0B30073B710 /* SecretTranslator.swift in Sources */, 8D069F69296447D000AB61A9 /* Peripheral.swift in Sources */, @@ -311,6 +318,7 @@ 8D069F672964475A00AB61A9 /* CentralManagerDelegate.swift in Sources */, 8D069F6D2964724700AB61A9 /* Characteristics.swift in Sources */, 0A62BB712938C1EC0092E47D /* Wallet.swift in Sources */, + E25800A42976BF8700968EA0 /* chunker.swift in Sources */, 0A62BB732938C1FB0092E47D /* Verifier.swift in Sources */, 8D069F6B29644B7C00AB61A9 /* PeripheralExtension.swift in Sources */, 8D179C8F29548B3A00017EE5 /* CryptoBoxImpl.swift in Sources */, diff --git a/ios/Openid4vpBle/Openid4vpBle.swift b/ios/Openid4vpBle/Openid4vpBle.swift index e8c8134d..ee9659e7 100644 --- a/ios/Openid4vpBle/Openid4vpBle.swift +++ b/ios/Openid4vpBle/Openid4vpBle.swift @@ -38,6 +38,7 @@ class Openid4vpBle: RCTEventEmitter { } return dictonary! } + @objc func getConnectionParametersDebug() -> String { return "GetConnectionParametersDebug" @@ -66,8 +67,11 @@ class Openid4vpBle: RCTEventEmitter { case "exchange-sender-info": print("EXCHANGE-SENDER-INFO") callback([]) - // Wallet.shared.registerCallbackForEvent(event: "EXCHANGE-SENDER-INFO", callback: callback) + //Wallet.shared.registerCallbackForEvent(event: "EXCHANGE-SENDER-INFO", callback: callback) Wallet.shared.writeIdentity() + case "send-vc": + callback([]) + Wallet.shared.sendData(data: messageComponents[1]) default: print("DEFAULT SEND: MESSAGE:: ", message) } @@ -80,7 +84,8 @@ class Openid4vpBle: RCTEventEmitter { print("Advertiser") case "discoverer": print("Discoverer") - Wallet.shared.central = Central() + Central.shared.initialize() + Wallet.shared.central = Central.shared Wallet.shared.registerCallbackForEvent(event: "CREATE_CONNECTION", callback: callback) default: print("DEFAULT CASE: MESSAGE:: ", mode) diff --git a/ios/Wallet/Wallet.swift b/ios/Wallet/Wallet.swift index 465cbe32..ba0e7ca9 100644 --- a/ios/Wallet/Wallet.swift +++ b/ios/Wallet/Wallet.swift @@ -1,4 +1,5 @@ import Foundation +import Gzip @objc(Wallet) @available(iOS 13.0, *) @@ -23,7 +24,6 @@ class Wallet: NSObject { } func registerCallbackForEvent(event: String, callback: @escaping RCTResponseSenderBlock) { - NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: event), object: nil, queue: nil) { [unowned self] notification in print("Handling notification for \(notification.name.rawValue)") callback([]) @@ -61,21 +61,37 @@ class Wallet: NSObject { } return data } - - @available(iOS 13.0, *) - func writeIdentity() { - print("::: write idendity called ::: ") - let publicKey = WalletCryptoBoxImpl().getPublicKey() - print("verifier pub key:::", self.verifierPublicKey) - guard let verifierPublicKey = self.verifierPublicKey else { - print("Write Identity - Found NO KEY") - return + + func sendData(data: String){ + var dataInBytes = Data(data.utf8) + var compressedBytes = try! dataInBytes.gzipped() + var encryptedData = secretTranslator?.encryptToSend(data: compressedBytes) + if (encryptedData != nil) { + DispatchQueue.main.async { + let transferHandler = TransferHandler.shared + transferHandler.initialize(initdData: encryptedData!) + let imsgBuilder = imessage(msgType: .INIT_RESPONSE_TRANSFER, data: encryptedData!) + transferHandler.sendMessage(message: imsgBuilder) + } + } else { + + } + } + @available(iOS 13.0, *) + func writeIdentity() { + print("::: write idendity called ::: ") + let publicKey = WalletCryptoBoxImpl().getPublicKey() + print("verifier pub key:::", self.verifierPublicKey) + guard let verifierPublicKey = self.verifierPublicKey else { + print("Write Identity - Found NO KEY") + return + } + self.secretTranslator = WalletCryptoBoxImpl().buildSecretsTranslator(verifierPublicKey: verifierPublicKey) + var iv = (self.secretTranslator?.initializationVector())! + central?.write(serviceUuid: Peripheral.SERVICE_UUID, charUUID: NetworkCharNums.identifyRequestCharacteristic, data: iv + publicKey) + NotificationCenter.default.post(name: Notification.Name(rawValue: "EXCHANGE-SENDER-INFO"), object: nil) } - self.secretTranslator = WalletCryptoBoxImpl().buildSecretsTranslator(verifierPublicKey: verifierPublicKey) - var iv = (self.secretTranslator?.initializationVector())! - central?.write(serviceUuid: Peripheral.SERVICE_UUID, charUUID: TransferService.identifyRequestCharacteristic, data: iv + publicKey) - NotificationCenter.default.post(name: Notification.Name(rawValue: "EXCHANGE-SENDER-INFO"), object: nil) - } + } -} + diff --git a/ios/Wallet/WalletViewModel.swift b/ios/Wallet/WalletViewModel.swift index dd48c17d..99494128 100644 --- a/ios/Wallet/WalletViewModel.swift +++ b/ios/Wallet/WalletViewModel.swift @@ -38,7 +38,7 @@ struct WalletViewModel { print("verifier pub key:::", BLEConstants.verifierPublicKey) secretTranslators = WalletCryptoBoxImpl().buildSecretsTranslator(verifierPublicKey: BLEConstants.verifierPublicKey) var iv = (secretTranslators?.initializationVector())! - central.write(serviceUuid: BLEConstants.SERVICE_UUID, charUUID: TransferService.identifyRequestCharacteristic, data: iv + publicKey) + central.write(serviceUuid: BLEConstants.SERVICE_UUID, charUUID: NetworkCharNums.identifyRequestCharacteristic, data: iv + publicKey) } mutating func setAdvIdentifier(advIdentifier: String) { @@ -51,3 +51,4 @@ struct WalletViewModel { BLEConstants.verifierPublicKey = publicKeyData } } + diff --git a/ios/ble/Utility/BLEConstants.swift b/ios/ble/Utility/BLEConstants.swift index 8ea606db..248edc3a 100644 --- a/ios/ble/Utility/BLEConstants.swift +++ b/ios/ble/Utility/BLEConstants.swift @@ -7,4 +7,7 @@ struct BLEConstants { static let SCAN_RESPONSE_SERVICE_UUID = CBUUID(string: "0000AB2A-0000-1000-8000-00805f9b34fb") static var ADV_IDENTIFIER = "" static var verifierPublicKey: Data = Data() + static var DEFAULT_CHUNK_SIZE = 185 + static var seqNumberReservedByteSize = 2 + static var mtuReservedByteSize = 2 } diff --git a/ios/ble/Utility/TransferHandler.swift b/ios/ble/Utility/TransferHandler.swift new file mode 100644 index 00000000..e2399aa1 --- /dev/null +++ b/ios/ble/Utility/TransferHandler.swift @@ -0,0 +1,158 @@ + +import Foundation + +@available(iOS 13.0, *) +class TransferHandler { + var data: Data? + private var currentState: States = States.UnInitialised + private var responseStartTimeInMillis: UInt64 = 0 + var chunker: Chunker? + + public static var shared = TransferHandler() + + func initialize(initdData: Data) { + data = initdData + } + + func sendMessage(message: imessage) { + handleMessage(msg: message) + } + deinit{ + print("deinit happend in transferh") + } + private func handleMessage(msg: imessage){ + if msg.msgType == .INIT_RESPONSE_TRANSFER { + var responseData = msg.data! + print("Total response size of data",responseData.count) + chunker = Chunker(chunkData: responseData, mtuSize: BLEConstants.DEFAULT_CHUNK_SIZE) + print("MTU found to be", BLEConstants.DEFAULT_CHUNK_SIZE) + currentState = States.ResponseSizeWritePending + sendMessage(message: imessage(msgType: .ResponseSizeWritePendingMessage, data: responseData, dataSize: responseData.count)) + } + else if msg.msgType == .ResponseSizeWritePendingMessage { + sendResponseSize(size: msg.dataSize!) + } + else if msg.msgType == .RESPONSE_SIZE_WRITE_SUCCESS { + responseStartTimeInMillis = Utils.currentTimeInMilliSeconds() + currentState = States.ResponseSizeWriteSuccess + initResponseChunkSend() + } else if msg.msgType == .INIT_RESPONSE_CHUNK_TRANSFER { + currentState = .ResponseWritePending + sendResponseChunk() + } + else if msg.msgType == .READ_TRANSMISSION_REPORT { + currentState = States.WaitingForTransferReport + requestTransmissionReport() + } + else if msg.msgType == .HANDLE_TRANSMISSION_REPORT { + currentState = States.HandlingTransferReport + var handleTransmissionReportMessage = msg.data + handleTransmissionReport(report: handleTransmissionReportMessage!) + } + else { + print("out of scope") + } + } + + private func requestTransmissionReport() { + var notifyObj: Data = Data() + Central.shared.write(serviceUuid: BLEConstants.SERVICE_UUID, charUUID: NetworkCharNums.semaphoreCharacteristic, data: withUnsafeBytes(of: 1.bigEndian) { Data($0) }) + NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "HANDLE_TRANSMISSION_REPORT"), object: nil, queue: nil) { [unowned self] notification in + print("Handling notification for \(notification.name.rawValue)") + notifyObj = notification.object as! Data + } + sendMessage(message: imessage(msgType: .HANDLE_TRANSMISSION_REPORT, data: notifyObj)) + } + + private func handleTransmissionReport(report: Data) { +// if (report.type == TransferReport.ReportType.SUCCESS) { +// currentState = States.TransferVerified +// transferListener.onResponseSent() +// print(logTag, "handleMessage: Successfully transferred vc in ${System.currentTimeMillis() - responseStartTimeInMillis}ms") +// } else if(report.type == TransferReport.ReportType.MISSING_CHUNKS && report.missingSequences != null && !isRetryFrame) { +// currentState = States.PartiallyTransferred +// this.sendMessage(InitRetryTransferMessage(report.missingSequences)) +// } else { +// this.sendMessage(ResponseTransferFailureMessage("Invalid Report")) +// } + print("report is :::", String(data: report, encoding: .utf8)) + } + + private func sendResponseSize(size: Int) { + // TODO: Send a stringified number in a byte array + let decimalString = String(size) + let d = decimalString.data(using: .utf8) + print(d!) + Central.shared.write(serviceUuid: Peripheral.SERVICE_UUID, charUUID: NetworkCharNums.responseSizeCharacteristic, data: d!) + NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "RESPONSE_SIZE_WRITE_SUCCESS"), object: nil, queue: nil) { [unowned self] notification in + print("Handling notification for \(notification.name.rawValue)") + sendMessage(message: imessage(msgType: .RESPONSE_SIZE_WRITE_SUCCESS, data: data)) + } + } + + private func initResponseChunkSend() { + print("initResponseChunkSend") + sendMessage(message: imessage(msgType: .INIT_RESPONSE_CHUNK_TRANSFER, data: data, dataSize: data?.count)) + } + + private func sendResponseChunk() { + if let chunker = chunker { + if chunker.isComplete() { + print("Data send complete") + sendMessage(message: imessage(msgType: .READ_TRANSMISSION_REPORT)) + return + } + + var done = false + while !done { + sleep(10) + let chunk = chunker.next() + if chunk.isEmpty { + done = true + sendMessage(message: imessage(msgType: .INIT_RESPONSE_CHUNK_TRANSFER, data: data, dataSize: data?.count)) + } + else { + Central.shared.write(serviceUuid: Peripheral.SERVICE_UUID, charUUID: NetworkCharNums.responseCharacteristic, data: chunk) + } + + } + } + } +} + +enum TransferMessageTypes { + case INIT_RESPONSE_TRANSFER + case ResponseSizeWritePendingMessage + case RESPONSE_SIZE_WRITE_SUCCESS + case INIT_RESPONSE_CHUNK_TRANSFER + case RESPONSE_TRANSFER_COMPLETE + case READ_TRANSMISSION_REPORT + case HANDLE_TRANSMISSION_REPORT +} + +struct imessage { + var msgType: TransferMessageTypes + var data: Data? + var dataSize: Int? +} + +enum States { + case UnInitialised + case ResponseSizeWritePending + case ResponseSizeWriteSuccess + case ResponseSizeWriteFailed + case ResponseWritePending + case ResponseWriteFailed + case TransferComplete + case WaitingForTransferReport + case HandlingTransferReport + case TransferVerified + case PartiallyTransferred +} + +enum SemaphoreMarker: Int { + case UnInitialised = 0 + case RequestReport = 1 + case Error = 2 + } + diff --git a/ios/ble/Utility/chunker.swift b/ios/ble/Utility/chunker.swift new file mode 100644 index 00000000..8920eac4 --- /dev/null +++ b/ios/ble/Utility/chunker.swift @@ -0,0 +1,118 @@ + + +import Foundation + +class Chunker { + + private var logTag = "Chunker" + private var chunksReadCounter: Int = 0 + private var preSlicedChunks: [Data] = [] + private var chunkData: Data? + private var mtuSize: Int = BLEConstants.DEFAULT_CHUNK_SIZE + private var chunkMetaSize = BLEConstants.seqNumberReservedByteSize + BLEConstants.mtuReservedByteSize + + init(chunkData: Data, mtuSize: Int?) { + self.chunkData = chunkData + self.mtuSize = mtuSize! + assignPreSlicedChunks() + } + + func getLastChunkByteCount(dataSize: Int) -> Int { + return dataSize % effectivePayloadSize + } + + func assignPreSlicedChunks(){ + print("preSlicedChunks called ::: ") + for i in 0.. Double { + var resulydouble = Double(dataSize)/Double(effectivePayloadSize) + return Double(ceill(resulydouble)) + } + + var lastChunkByteCount: Int { + return getLastChunkByteCount(dataSize: chunkData!.count) + } + + var totalChunkCount: Int { + return Int(getTotalChunkCount(dataSize: chunkData!.count)) + } + + var effectivePayloadSize: Int { + return mtuSize - chunkMetaSize + } + + func next() -> Data { + var seqNumber = chunksReadCounter + chunksReadCounter += 1 + if seqNumber <= totalChunkCount - 1 { + return (preSlicedChunks[seqNumber]) + } + else + { + return Data() + } + } + + func chunkBySequenceNumber(num: Int) -> Data { + return (preSlicedChunks[num]) + } + + private func chunk(seqNumber: Int) -> Data { + let fromIndex = seqNumber * effectivePayloadSize + if (seqNumber == (totalChunkCount - 1) && lastChunkByteCount > 0) { + print( "fetching last chunk") + let chunkLength = lastChunkByteCount + chunkMetaSize + return frameChunk(seqNumber: seqNumber, chunkLength: chunkLength, fromIndex: fromIndex, toIndex: fromIndex + lastChunkByteCount) + } else { + let toIndex = (seqNumber + 1) * effectivePayloadSize + return frameChunk(seqNumber: seqNumber, chunkLength: mtuSize, fromIndex: fromIndex, toIndex: toIndex) + } + } + + /* + <------------------------------------------------------- MTU -------------------------------------------------------------------> + +-----------------------+-----------------------------+-------------------------------------------------------------------------+ + | | | | + | chunk sequence no | total chunk length | chunk payload | + | (2 bytes) | (2 bytes) | (upto MTU-4 bytes) | + | | | | + +-----------------------+-----------------------------+-------------------------------------------------------------------------+ + */ + + private func frameChunk(seqNumber: Int, chunkLength: Int, fromIndex: Int, toIndex: Int) -> Data { + print("fetching chunk size:",toIndex,"-", fromIndex,"}, chunkSequenceNumber(0-indexed):", seqNumber) +// return intToTwoBytesBigEndian(num: seqNumber) + intToTwoBytesBigEndian(num: chunkLength) + chunkData!.subdata(in: fromIndex.. Bool { + let isComplete = chunksReadCounter > (totalChunkCount - 1) + if isComplete { + print("isComplete: true, totalChunks: $totalChunkCount , chunkReadCounter(1-indexed): $chunksReadCounter") + } + return isComplete + } + +// func intToTwoBytesBigEndian(num: Int) -> [UInt8] { +// if num < 256 { +// let minValue: UInt8 = 0 +// return [minValue, UInt8(num)] +// } +// return [UInt8(num/256), UInt8(num%256)] +// } + + func intToBytes(_ value: UInt16) -> Data { + var value = value.bigEndian + return Data(bytes: &value, count: MemoryLayout.size) + } +} + diff --git a/ios/ble/central/Central.swift b/ios/ble/central/Central.swift index 61b00f73..81c0f916 100644 --- a/ios/ble/central/Central.swift +++ b/ios/ble/central/Central.swift @@ -9,12 +9,14 @@ class Central: NSObject, CBCentralManagerDelegate { var connectedPeripheral: CBPeripheral? var transferCharacteristic: CBCharacteristic? var writeCharacteristic: CBCharacteristic? - var identifyRequestCharacteristic: CBCharacteristic? + var identityRequestCharacteristic: CBCharacteristic? - var chars: [String: CBCharacteristic] = [:] + var cbCharacteristics: [String: CBCharacteristic] = [:] - override init() { - super.init() + + public static var shared = Central() + + func initialize() { centralManager = CBCentralManager(delegate: self, queue: nil) } @@ -38,30 +40,33 @@ class Central: NSObject, CBCentralManagerDelegate { } func write(serviceUuid: CBUUID, charUUID: CBUUID, data: Data) { - if chars.contains(where: { key, value in - if key == charUUID.uuidString { return true } - return false - }) { - print("Value in chars... stopping write") - return - } +// if chars.contains(where: { key, value in +// if key == charUUID.uuidString { return true } +// return false +// }) { +// print("Value in chars... stopping write") +// return +// } if let connectedPeripheral = connectedPeripheral { if connectedPeripheral.canSendWriteWithoutResponse { - guard let writeCharacteristic = self.identifyRequestCharacteristic else { - print("Write characteristic is NIL") + guard let characteristic = self.cbCharacteristics[charUUID.uuidString] else { + print("Did not find the characteristic to write") return } let mtu = connectedPeripheral.maximumWriteValueLength(for: .withResponse) print("Write MTU: ", mtu) let bytesToCopy: size_t = min(mtu, data.count) let messageData = Data(bytes: Array(data), count: bytesToCopy) - connectedPeripheral.writeValue(messageData, for: writeCharacteristic, type: .withResponse) + // TBD: Make it big!! + connectedPeripheral.writeValue(messageData, for: characteristic, type: .withResponse) } } } - +/* func stopWritingToCharacteristic(characteristic: CBCharacteristic) { self.chars[characteristic.uuid.uuidString] = characteristic } + */ } + diff --git a/ios/ble/central/PeripheralDelegate.swift b/ios/ble/central/PeripheralDelegate.swift index eee6bc02..175e9604 100644 --- a/ios/ble/central/PeripheralDelegate.swift +++ b/ios/ble/central/PeripheralDelegate.swift @@ -4,7 +4,6 @@ import os @available(iOS 13.0, *) extension Central: CBPeripheralDelegate { - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { if let error = error { os_log("Error while discovering services: %s", error.localizedDescription) @@ -23,28 +22,36 @@ extension Central: CBPeripheralDelegate { os_log("Error discovering Characteristics: %s", error.localizedDescription) return } - guard let serviceCharacteristics = service.characteristics else { return } for characteristic in serviceCharacteristics { - if characteristic.uuid == TransferService.characteristicUUID { - self.transferCharacteristic = characteristic - peripheral.setNotifyValue(true, for: characteristic) - } - if characteristic.uuid == TransferService.writeCharacteristic { - print("Found write characteristic") - self.writeCharacteristic = characteristic - // No notify required, right? - } - if characteristic.uuid == TransferService.identifyRequestCharacteristic { - self.identifyRequestCharacteristic = characteristic -// sendPublicKey() -// print(characteristic) - } + // store a reference to the discovered characteristic in the Central for write. + print("Characteristic UUID:: ", characteristic.uuid.uuidString) + self.cbCharacteristics[characteristic.uuid.uuidString] = characteristic + + // TODO - subscribe to the characteristics for (2035, 2036, 2037) + + // if characteristic.uuid == TransferService.characteristicUUID { + // self.transferCharacteristic = characteristic + // peripheral.setNotifyValue(true, for: characteristic) + // } + // if characteristic.uuid == TransferService.writeCharacteristic { + // print("Found write characteristic") + // // kludge: create a static side-effect for default chunk size + // BLEConstants.DEFAULT_CHUNK_SIZE = peripheral.maximumWriteValueLength(for: .withResponse) + // print("MTU set to be", BLEConstants.DEFAULT_CHUNK_SIZE) + // self.writeCharacteristic = characteristic + // // No notify required, right? + // } + // if characteristic.uuid == TransferService.identifyRequestCharacteristic { + // self.identifyRequestCharacteristic = characteristic + //// sendPublicKey() + //// print(characteristic) } NotificationCenter.default.post(name: Notification.Name(rawValue: "CREATE_CONNECTION"), object: nil) } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + print("Central was able to update value for the characteristic: ", characteristic.uuid.uuidString) if let error = error { os_log("Unable to recieve updates from device: %s", error.localizedDescription) return @@ -60,7 +67,19 @@ extension Central: CBPeripheralDelegate { print("TS::: Identify:::", characteristic.uuid) EventEmitter.sharedInstance.emitNearbyMessage(event: "exchange-receiver-info", data: "{\"deviceName\":\"verifier\"}") print("Central was able to write value for the characteristic: ", characteristic.uuid.uuidString) + if characteristic.uuid.uuidString == "2033" { + NotificationCenter.default.post(name: Notification.Name(rawValue: "RESPONSE_SIZE_WRITE_SUCCESS"), object: nil) + } else if characteristic.uuid.uuidString == "2035" { + let report = characteristic.value + NotificationCenter.default.post(name: Notification.Name(rawValue: "HANDLE_TRANSMISSION_REPORT"), object: report) + } + else { + + } } - func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {} + func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) { + + } } + diff --git a/ios/ble/peripheral/Characteristics.swift b/ios/ble/peripheral/Characteristics.swift index b2e2536c..b89946d4 100644 --- a/ios/ble/peripheral/Characteristics.swift +++ b/ios/ble/peripheral/Characteristics.swift @@ -58,3 +58,14 @@ struct TransferService { static let characteristicUUID = CBUUID(string: "00002032-0000-1000-8000-00805f9b34fb") //read characteristics static let writeCharacteristic = CBUUID(string: "00002031-0000-1000-8000-00805f9b34fb") } + +struct NetworkCharNums { + static let identifyRequestCharacteristic = CBUUID(string: "2030") + static let requestSizeCharacteristic = CBUUID(string: "2031") + static let requestCharacteristic = CBUUID(string: "2032") + static let responseSizeCharacteristic = CBUUID(string: "2033") + static let responseCharacteristic = CBUUID(string: "2034") + static let semaphoreCharacteristic = CBUUID(string: "2035") + static let verificationStatusCharacteristic = CBUUID(string: "2036") +} + diff --git a/ios/ble/peripheral/Utils.swift b/ios/ble/peripheral/Utils.swift index b3e18e08..ba8f3b24 100644 --- a/ios/ble/peripheral/Utils.swift +++ b/ios/ble/peripheral/Utils.swift @@ -8,4 +8,10 @@ struct Utils { return CBMutableCharacteristic(type: keyUUID, properties: chrTuple.properties, value: chrTuple.value, permissions: chrTuple.permissions) } } + + static func currentTimeInMilliSeconds()-> UInt64 { + let currentDate = Date() + let since1970 = currentDate.timeIntervalSince1970 + return UInt64(since1970 * 1000) + } } diff --git a/react-native-openid4vp-ble.podspec b/react-native-openid4vp-ble.podspec index 8979b455..a64c2557 100644 --- a/react-native-openid4vp-ble.podspec +++ b/react-native-openid4vp-ble.podspec @@ -17,6 +17,7 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" + s.dependency "GzipSwift" s.dependency "CrcSwift", "~> 0.0.3" # Don't install the dependencies when we run `pod install` in the old architecture.