diff --git a/android/src/main/java/io/twentysixty/rn/eidreader/EIdReaderModule.kt b/android/src/main/java/io/twentysixty/rn/eidreader/EIdReaderModule.kt index 8aebc9e..a2fe172 100644 --- a/android/src/main/java/io/twentysixty/rn/eidreader/EIdReaderModule.kt +++ b/android/src/main/java/io/twentysixty/rn/eidreader/EIdReaderModule.kt @@ -57,6 +57,7 @@ class EIdReaderModule(reactContext: ReactApplicationContext) : private val jsonToReactMap = JsonToReactMap() private var _promise: Promise? = null private var _dialog: AlertDialog? = null + private var labels: ReadableMap? = null init { reactApplicationContext.addLifecycleEventListener(this) @@ -171,7 +172,8 @@ class EIdReaderModule(reactContext: ReactApplicationContext) : ) currentActivity?.runOnUiThread(Runnable { - _dialog?.setMessage("Reading. Hold your document...") + val message = labels?.getString("reading") ?: "Reading. Hold your document..." + _dialog?.setMessage(message) }) val result = nfcPassportReader.readPassport(IsoDep.get(tag), bacKey, includeImages, includeRawData) @@ -199,7 +201,8 @@ class EIdReaderModule(reactContext: ReactApplicationContext) : private fun reject(e: Exception) { currentActivity?.runOnUiThread(Runnable { - _dialog?.setMessage("Sorry, there was a problem reading the passport. Please try again") + val message = labels?.getString("error") ?: "Sorry, there was a problem reading the passport. Please try again" + _dialog?.setMessage(message) }) stopReading(false) _promise?.reject(e) @@ -210,6 +213,7 @@ class EIdReaderModule(reactContext: ReactApplicationContext) : readableMap?.let { try { _promise = promise + labels = readableMap?.getMap("labels") val mrzMap = readableMap?.getMap("mrzInfo") val mrzExpirationDate = mrzMap?.getString("expirationDate") val mrzBirthDate = mrzMap?.getString("birthDate") @@ -230,11 +234,14 @@ class EIdReaderModule(reactContext: ReactApplicationContext) : val currentActivity = currentActivity if (currentActivity != null) { currentActivity?.runOnUiThread(Runnable { + val title = labels?.getString("title") ?: "Ready to Scan" + val message = labels?.getString("requestPresentPassport") ?: "Hold your phone near an NFC enabled passport" + val cancelButton = labels?.getString("cancelButton") ?: "Cancel" val builder = AlertDialog.Builder(currentActivity) - builder.setTitle("Ready to Scan") - .setMessage("Hold your phone near an NFC enabled passport") + builder.setTitle(title) + .setMessage(message) .setCancelable(true) - .setNegativeButton("Cancel") { dialog, _ -> + .setNegativeButton(cancelButton) { dialog, _ -> stopReading() val reactMap = jsonToReactMap.convertJsonToMap(JSONObject("{status: 'Canceled' }")) diff --git a/ios/EidReader.swift b/ios/EidReader.swift index 99ee691..9c0fea0 100644 --- a/ios/EidReader.swift +++ b/ios/EidReader.swift @@ -31,6 +31,7 @@ class EIdReader: RCTEventEmitter { // TODO isReading = true + let labels = params["labels"] as? NSDictionary let mrzInfo = params["mrzInfo"] as! NSDictionary let expirationDate = mrzInfo["expirationDate"] as! String let birthDate = mrzInfo["birthDate"] as! String @@ -44,16 +45,7 @@ class EIdReader: RCTEventEmitter { Task { var eidReadResult: [String: Any] = [:] do { - let customMessageHandler : (NFCViewDisplayMessage)->String? = { (displayMessage) in - switch displayMessage { - case .requestPresentPassport: - return "Hold your iPhone near an NFC enabled passport." - default: - // Return nil for all other messages so we use the provided default - return nil - } - } - let passport = try await passportReader.readPassport( mrzKey: mrzKey, useExtendedMode: false, customDisplayMessage:customMessageHandler) + let passport = try await passportReader.readPassport( mrzKey: mrzKey, useExtendedMode: false, labels: labels) var data: [String: Any] = [:] diff --git a/ios/NFCPassportReader/BACHandler.swift b/ios/NFCPassportReader/BACHandler.swift index 802ce32..880d7b0 100644 --- a/ios/NFCPassportReader/BACHandler.swift +++ b/ios/NFCPassportReader/BACHandler.swift @@ -56,7 +56,7 @@ public class BACHandler { let maResponse = try await tagReader.doMutualAuthentication(cmdData: Data(cmd_data)) Logger.bac.debug( "DATA - \(maResponse.data)" ) guard maResponse.data.count > 0 else { - throw NFCPassportReaderError.InvalidMRZKey + throw NFCPassportReaderError.InvalidMRZKey() } let (KSenc, KSmac, ssc) = try self.sessionKeys(data: [UInt8](maResponse.data)) diff --git a/ios/NFCPassportReader/DataGroups/DataGroup.swift b/ios/NFCPassportReader/DataGroups/DataGroup.swift index 1db0235..7b77d56 100644 --- a/ios/NFCPassportReader/DataGroups/DataGroup.swift +++ b/ios/NFCPassportReader/DataGroups/DataGroup.swift @@ -37,7 +37,7 @@ public class DataGroup { // Fix for some passports that may have invalid data - ensure that we do have data! guard data.count > pos else { - throw NFCPassportReaderError.TagNotValid + throw NFCPassportReaderError.TagNotValid() } if binToHex(data[pos]) & 0x0F == 0x0F { diff --git a/ios/NFCPassportReader/Errors.swift b/ios/NFCPassportReader/Errors.swift index d994b36..7c2827e 100644 --- a/ios/NFCPassportReader/Errors.swift +++ b/ios/NFCPassportReader/Errors.swift @@ -28,11 +28,11 @@ public enum NFCPassportReaderError: Error { case UnknownTag case UnknownImageFormat case NotImplemented - case TagNotValid - case ConnectionError + case TagNotValid(String? = nil) + case ConnectionError(String? = nil) case UserCanceled - case InvalidMRZKey - case MoreThanOneTagFound + case InvalidMRZKey(String? = nil) + case MoreThanOneTagFound(String? = nil) case InvalidHashAlgorithmSpecified case UnsupportedCipherAlgorithm case UnsupportedMappingType diff --git a/ios/NFCPassportReader/NFCViewDisplayMessage.swift b/ios/NFCPassportReader/NFCViewDisplayMessage.swift index 2539817..a497538 100644 --- a/ios/NFCPassportReader/NFCViewDisplayMessage.swift +++ b/ios/NFCPassportReader/NFCViewDisplayMessage.swift @@ -9,45 +9,46 @@ import Foundation @available(iOS 13, macOS 10.15, *) public enum NFCViewDisplayMessage { - case requestPresentPassport - case authenticatingWithPassport(Int) - case readingDataGroupProgress(DataGroupId, Int) - case error(NFCPassportReaderError) - case activeAuthentication - case successfulRead + case requestPresentPassport(String? = nil) + case authenticatingWithPassport(Int, String? = nil) + case readingDataGroupProgress(DataGroupId, Int, String? = nil) + case error(NFCPassportReaderError, String? = nil) + case activeAuthentication(String? = nil) + case successfulRead(String? = nil) } @available(iOS 13, macOS 10.15, *) extension NFCViewDisplayMessage { public var description: String { switch self { - case .requestPresentPassport: - return "Hold your iPhone near an NFC enabled passport." - case .authenticatingWithPassport(let progress): + case .requestPresentPassport(let label): + return label ?? "Hold your iPhone near an NFC enabled passport." + case .authenticatingWithPassport(let progress, let label): let progressString = handleProgress(percentualProgress: progress) - return "Authenticating with passport.....\n\n\(progressString)" - case .readingDataGroupProgress(let dataGroup, let progress): + let message = "\(label ?? "Authenticating with passport...")\n\n\(progressString)" + return message + case .readingDataGroupProgress(let dataGroup, let progress, let label): let progressString = handleProgress(percentualProgress: progress) - return "Reading \(dataGroup).....\n\n\(progressString)" - case .error(let tagError): + return "\(label ?? "Reading...") \(dataGroup)n\n\(progressString)" + case .error(let tagError, let label): switch tagError { - case NFCPassportReaderError.TagNotValid: - return "Tag not valid." - case NFCPassportReaderError.MoreThanOneTagFound: - return "More than 1 tags was found. Please present only 1 tag." - case NFCPassportReaderError.ConnectionError: - return "Connection error. Please try again." - case NFCPassportReaderError.InvalidMRZKey: + case NFCPassportReaderError.TagNotValid(let label): + return label ?? "Tag not valid." + case NFCPassportReaderError.MoreThanOneTagFound(let label): + return label ?? "More than 1 tags was found. Please present only 1 tag." + case NFCPassportReaderError.ConnectionError(let label): + return label ?? "Connection error. Please try again." + case NFCPassportReaderError.InvalidMRZKey(let label): return "MRZ Key not valid for this document." case NFCPassportReaderError.ResponseError(let description, let sw1, let sw2): - return "Sorry, there was a problem reading the passport. \(description) - (0x\(sw1), 0x\(sw2)" + return "\(label ?? "Sorry, there was a problem reading the passport. Please try again.") \(description) - (0x\(sw1), 0x\(sw2)" default: - return "Sorry, there was a problem reading the passport. Please try again" + return label ?? "Sorry, there was a problem reading the passport. Please try again" } - case .activeAuthentication: - return "Authenticating....." - case .successfulRead: - return "Passport read successfully" + case .activeAuthentication(let label): + return label ?? "Authenticating..." + case .successfulRead(let label): + return label ?? "Passport read successfully" } } diff --git a/ios/NFCPassportReader/PassportReader.swift b/ios/NFCPassportReader/PassportReader.swift index f9df2a1..7a75ad0 100644 --- a/ios/NFCPassportReader/PassportReader.swift +++ b/ios/NFCPassportReader/PassportReader.swift @@ -15,6 +15,7 @@ import CoreNFC @available(iOS 15, *) public class PassportReader : NSObject { + private var labels: NSDictionary? = nil private var pendingPassportModel: NFCPassportModel? = nil private typealias NFCCheckedContinuation = CheckedContinuation private var nfcContinuation: NFCCheckedContinuation? @@ -64,8 +65,8 @@ public class PassportReader : NSObject { dataAmountToReadOverride = amount } - public func readPassport( mrzKey : String, tags : [DataGroupId] = [], skipSecureElements : Bool = true, skipCA : Bool = false, skipPACE : Bool = false, useExtendedMode : Bool = false, customDisplayMessage : ((NFCViewDisplayMessage) -> String?)? = nil) async throws -> NFCPassportModel { - + public func readPassport( mrzKey : String, tags : [DataGroupId] = [], skipSecureElements : Bool = true, skipCA : Bool = false, skipPACE : Bool = false, useExtendedMode : Bool = false, customDisplayMessage : ((NFCViewDisplayMessage) -> String?)? = nil, labels: NSDictionary?) async throws -> NFCPassportModel { + self.labels = labels self.passport = NFCPassportModel() self.mrzKey = mrzKey self.skipCA = skipCA @@ -98,7 +99,7 @@ public class PassportReader : NSObject { if NFCTagReaderSession.readingAvailable { readerSession = NFCTagReaderSession(pollingOption: [.iso14443], delegate: self, queue: nil) - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.requestPresentPassport ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.requestPresentPassport(labels?["requestPresentPassport"] as? String)) readerSession?.begin() } @@ -171,8 +172,8 @@ extension PassportReader : NFCTagReaderSessionDelegate { if tags.count > 1 { Logger.passportReader.debug( "tagReaderSession:more than 1 tag detected! - \(tags)" ) - let errorMessage = NFCViewDisplayMessage.error(.MoreThanOneTagFound) - self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.MoreThanOneTagFound) + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.MoreThanOneTagFound(self.labels?["moreThanOneTagFound"]as? String)) + self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.MoreThanOneTagFound(self.labels?["moreThanOneTagFound"] as? String)) return } @@ -183,9 +184,8 @@ extension PassportReader : NFCTagReaderSessionDelegate { passportTag = tag default: Logger.passportReader.debug( "tagReaderSession:invalid tag detected!!!" ) - - let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.TagNotValid) - self.invalidateSession(errorMessage:errorMessage, error: NFCPassportReaderError.TagNotValid) + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.TagNotValid(self.labels?["tagNotValid"] as? String)) + self.invalidateSession(errorMessage:errorMessage, error: NFCPassportReaderError.TagNotValid(self.labels?["tagNotValid"] as? String)) return } @@ -194,7 +194,7 @@ extension PassportReader : NFCTagReaderSessionDelegate { try await session.connect(to: tag) Logger.passportReader.debug( "tagReaderSession:connected to tag - starting authentication" ) - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.authenticatingWithPassport(0) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.authenticatingWithPassport(0, self.labels?["authenticatingWithPassport"] as? String) ) let tagReader = TagReader(tag:passportTag) @@ -204,20 +204,20 @@ extension PassportReader : NFCTagReaderSessionDelegate { tagReader.progress = { [unowned self] (progress) in if let dgId = self.currentlyReadingDataGroup { - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, progress) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, progress, self.labels?["reading"] as? String) ) } else { - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.authenticatingWithPassport(progress) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.authenticatingWithPassport(progress, self.labels?["reading"] as? String) ) } } try await self.startReading( tagReader : tagReader) } catch let error as NFCPassportReaderError { - let errorMessage = NFCViewDisplayMessage.error(error) + let errorMessage = NFCViewDisplayMessage.error(error, self.labels?["error"] as? String) self.invalidateSession(errorMessage: errorMessage, error: error) } catch let error { Logger.passportReader.debug( "tagReaderSession:failed to connect to tag - \(error.localizedDescription)" ) - let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError(self.labels?["error"] as? String)) self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.Unknown(error)) } } @@ -264,7 +264,7 @@ extension PassportReader { try await doActiveAuthenticationIfNeccessary(tagReader : tagReader) - self.updateReaderSessionMessage(alertMessage: NFCViewDisplayMessage.successfulRead) + self.updateReaderSessionMessage(alertMessage: NFCViewDisplayMessage.successfulRead(self.labels?["successfulRead"] as? String)) self.shouldNotReportNextReaderSessionInvalidationErrorUserCanceled = true self.readerSession?.invalidate() @@ -279,7 +279,7 @@ extension PassportReader { guard self.passport.activeAuthenticationSupported else { return } - self.updateReaderSessionMessage(alertMessage: NFCViewDisplayMessage.activeAuthentication) + self.updateReaderSessionMessage(alertMessage: NFCViewDisplayMessage.activeAuthentication(self.labels?["activeAuthentication"] as? String)) Logger.passportReader.info( "Performing Active Authentication" ) @@ -309,7 +309,7 @@ extension PassportReader { // Read COM var DGsToRead = [DataGroupId]() - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(.COM, 0) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(.COM, 0, self.labels?["reading"] as? String) ) if let com = try await readDataGroup(tagReader:tagReader, dgId:.COM) as? COM { self.passport.addDataGroup( .COM, dataGroup:com ) @@ -353,7 +353,7 @@ extension PassportReader { DGsToRead = DGsToRead.filter { dataGroupsToRead.contains($0) } } for dgId in DGsToRead { - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, 0) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, 0, self.labels?["reading"] as? String) ) if let dg = try await readDataGroup(tagReader:tagReader, dgId:dgId) { self.passport.addDataGroup( dgId, dataGroup:dg ) } @@ -367,7 +367,7 @@ extension PassportReader { var readAttempts = 0 var nfcPassportReaderError: NFCPassportReaderError - self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, 0) ) + self.updateReaderSessionMessage( alertMessage: NFCViewDisplayMessage.readingDataGroupProgress(dgId, 0, self.labels?["reading"] as? String) ) repeat { do { diff --git a/ios/NFCPassportReader/TagReader.swift b/ios/NFCPassportReader/TagReader.swift index 5a9e660..23e86d3 100644 --- a/ios/NFCPassportReader/TagReader.swift +++ b/ios/NFCPassportReader/TagReader.swift @@ -289,7 +289,7 @@ public class TagReader { Logger.tagReader.error( "Error reading tag: sw1 - 0x\(binToHexRep(sw1)), sw2 - 0x\(binToHexRep(sw2))" ) let tagError: NFCPassportReaderError if (rep.sw1 == 0x63 && rep.sw2 == 0x00) { - tagError = NFCPassportReaderError.InvalidMRZKey + tagError = NFCPassportReaderError.InvalidMRZKey() } else { let errorMsg = self.decodeError(sw1: rep.sw1, sw2: rep.sw2) Logger.tagReader.error( "reason: \(errorMsg)" ) diff --git a/src/index.tsx b/src/index.tsx index 3e74d28..0ae7832 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -30,6 +30,19 @@ export type StartReadingParams = { }; includeImages?: boolean; // default: false includeRawData?: boolean; // default: false + labels?: { + title?: string; + cancelButton?: string; + requestPresentPassport?: string; + authenticatingWithPassport?: string; + reading?: string; + activeAuthentication?: string; + successfulRead?: string; + tagNotValid?: string; + moreThanOneTagFound?: string; + invalidMRZKey?: string; + error?: string; + }; }; export type EidReadStatus = 'OK' | 'Error' | 'Canceled';