From 66967cee1575e4f2d705749576cc76c22dd1e10f Mon Sep 17 00:00:00 2001 From: Laura Geiger Date: Thu, 2 May 2024 13:37:06 +0200 Subject: [PATCH 1/5] NFC-286 Remove auto-formatting [NFC-386] Add changes requested in PR --- Sources/NFCPassportReader/Errors.swift | 2 ++ .../NFCPassportReader/PassportReader.swift | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Sources/NFCPassportReader/Errors.swift b/Sources/NFCPassportReader/Errors.swift index d994b368..b997b35d 100644 --- a/Sources/NFCPassportReader/Errors.swift +++ b/Sources/NFCPassportReader/Errors.swift @@ -30,6 +30,7 @@ public enum NFCPassportReaderError: Error { case NotImplemented case TagNotValid case ConnectionError + case TimeOutError case UserCanceled case InvalidMRZKey case MoreThanOneTagFound @@ -64,6 +65,7 @@ public enum NFCPassportReaderError: Error { case .NotImplemented: return "NotImplemented" case .TagNotValid: return "TagNotValid" case .ConnectionError: return "ConnectionError" + case .TimeOutError: return "TimeOutError" case .UserCanceled: return "UserCanceled" case .InvalidMRZKey: return "InvalidMRZKey" case .MoreThanOneTagFound: return "MoreThanOneTagFound" diff --git a/Sources/NFCPassportReader/PassportReader.swift b/Sources/NFCPassportReader/PassportReader.swift index 773f469b..ac66da39 100644 --- a/Sources/NFCPassportReader/PassportReader.swift +++ b/Sources/NFCPassportReader/PassportReader.swift @@ -135,6 +135,9 @@ extension PassportReader : NFCTagReaderSessionDelegate { case NFCReaderError.readerSessionInvalidationErrorUserCanceled: Logger.passportReader.error( " - User cancelled session" ) userError = NFCPassportReaderError.UserCanceled + case NFCReaderError.readerSessionInvalidationErrorSessionTimeout: + Logger.passportReader.error(" - Session timeout") + userError = NFCPassportReaderError.TimeOutError default: Logger.passportReader.error( " - some other error - \(readerError.localizedDescription)" ) userError = NFCPassportReaderError.UnexpectedError @@ -199,10 +202,20 @@ extension PassportReader : NFCTagReaderSessionDelegate { } catch let error as NFCPassportReaderError { let errorMessage = NFCViewDisplayMessage.error(error) self.invalidateSession(errorMessage: errorMessage, error: error) - } catch let error { + } catch { Logger.passportReader.debug( "tagReaderSession:failed to connect to tag - \(error.localizedDescription)" ) - let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) - self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.Unknown(error)) + + if let nfcError = error as? NFCReaderError { + // .readerTransceiveErrorTagResponseError is thrown when a "connection lost" scenario is forced by moving the phone away from the NFC chip + // .readerTransceiveErrorTagConnectionLost is never thrown for this scenario, but added for the sake of completeness + if nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagResponseError.rawValue || nfc.errorCode == NFCReaderError.readerTransceiveErrorTagConnectionLost.rawValue { + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) + self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.ConnectionError) + } + } else { + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.Unknown(error)) + self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.Unknown(error)) + } } } } From de11f70de2d127c20c8b1f703a06cf108df57431 Mon Sep 17 00:00:00 2001 From: Laura Geiger Date: Mon, 6 May 2024 10:25:17 +0200 Subject: [PATCH 2/5] [NFC-386] Add changes requested in PR --- Sources/NFCPassportReader/PassportReader.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/NFCPassportReader/PassportReader.swift b/Sources/NFCPassportReader/PassportReader.swift index ac66da39..58c1fa07 100644 --- a/Sources/NFCPassportReader/PassportReader.swift +++ b/Sources/NFCPassportReader/PassportReader.swift @@ -208,7 +208,7 @@ extension PassportReader : NFCTagReaderSessionDelegate { if let nfcError = error as? NFCReaderError { // .readerTransceiveErrorTagResponseError is thrown when a "connection lost" scenario is forced by moving the phone away from the NFC chip // .readerTransceiveErrorTagConnectionLost is never thrown for this scenario, but added for the sake of completeness - if nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagResponseError.rawValue || nfc.errorCode == NFCReaderError.readerTransceiveErrorTagConnectionLost.rawValue { + if nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagResponseError.rawValue || nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagConnectionLost.rawValue { let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.ConnectionError) } From f1b13a7516778d64349fc2935666a1f30706ea18 Mon Sep 17 00:00:00 2001 From: laurageiger-mohemian <165795696+laurageiger-mohemian@users.noreply.github.com> Date: Fri, 24 May 2024 11:24:59 +0200 Subject: [PATCH 3/5] [NFC-395] Add delegate for tracking NFC detection (#2) * [NFC-395] Add delegate for tracking NFC detection * NFC-395 Changes requested in PR * NFC-395 Add changes requested in PR --- Sources/NFCPassportReader/PassportReader.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/NFCPassportReader/PassportReader.swift b/Sources/NFCPassportReader/PassportReader.swift index 58c1fa07..4d720392 100644 --- a/Sources/NFCPassportReader/PassportReader.swift +++ b/Sources/NFCPassportReader/PassportReader.swift @@ -13,11 +13,17 @@ import OSLog import UIKit import CoreNFC +@available(iOS 15, *) +public protocol PassportReaderTrackingDelegate: AnyObject { + func nfcTagDetected() +} + @available(iOS 15, *) public class PassportReader : NSObject { private typealias NFCCheckedContinuation = CheckedContinuation private var nfcContinuation: NFCCheckedContinuation? + public weak var trackingDelegate: PassportReaderTrackingDelegate? private var passport : NFCPassportModel = NFCPassportModel() private var readerSession: NFCTagReaderSession? @@ -290,6 +296,7 @@ extension PassportReader { func doBACAuthentication(tagReader : TagReader) async throws { self.currentlyReadingDataGroup = nil + trackingDelegate?.nfcTagDetected() Logger.passportReader.info( "Starting Basic Access Control (BAC)" ) self.passport.BACStatus = .failed From 6dddb832f2c1b24951f8f52fc1546ad54772f403 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 1 Jul 2024 13:59:22 +0200 Subject: [PATCH 4/5] [AXC-3089] Add more tracking for chip access phase (#3) * Add more tracking for chip access phase * Bubble up parsed card access instad of raw data --- .../NFCPassportReader/PassportReader.swift | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/Sources/NFCPassportReader/PassportReader.swift b/Sources/NFCPassportReader/PassportReader.swift index 4d720392..6b2e6d79 100644 --- a/Sources/NFCPassportReader/PassportReader.swift +++ b/Sources/NFCPassportReader/PassportReader.swift @@ -16,6 +16,25 @@ import CoreNFC @available(iOS 15, *) public protocol PassportReaderTrackingDelegate: AnyObject { func nfcTagDetected() + func readCardAccess(cardAccess: CardAccess) + func paceStarted() + func paceSucceeded() + func paceFailed() + func bacStarted() + func bacSucceeded() + func bacFailed() +} + +@available(iOS 15, *) +extension PassportReaderTrackingDelegate { + func nfcTagDetected() { /* default implementation */ } + func readCardAccess(cardAccess: CardAccess) { /* default implementation */ } + func paceStarted() { /* default implementation */ } + func paceSucceeded() { /* default implementation */ } + func paceFailed() { /* default implementation */ } + func bacStarted() { /* default implementation */ } + func bacSucceeded() { /* default implementation */ } + func bacFailed() { /* default implementation */ } } @available(iOS 15, *) @@ -235,21 +254,30 @@ extension PassportReader : NFCTagReaderSessionDelegate { extension PassportReader { func startReading(tagReader : TagReader) async throws -> NFCPassportModel { + trackingDelegate?.nfcTagDetected() if !skipPACE { do { + trackingDelegate?.paceStarted() + let data = try await tagReader.readCardAccess() Logger.passportReader.debug( "Read CardAccess - data \(binToHexRep(data))" ) let cardAccess = try CardAccess(data) passport.cardAccess = cardAccess - + + trackingDelegate?.readCardAccess(cardAccess: cardAccess) + Logger.passportReader.info( "Starting Password Authenticated Connection Establishment (PACE)" ) let paceHandler = try PACEHandler( cardAccess: cardAccess, tagReader: tagReader ) try await paceHandler.doPACE(mrzKey: mrzKey ) passport.PACEStatus = .success Logger.passportReader.debug( "PACE Succeeded" ) + + trackingDelegate?.paceSucceeded() } catch { + trackingDelegate?.paceFailed() + passport.PACEStatus = .failed Logger.passportReader.error( "PACE Failed - falling back to BAC" ) } @@ -259,7 +287,17 @@ extension PassportReader { // If either PACE isn't supported, we failed whilst doing PACE or we didn't even attempt it, then fall back to BAC if passport.PACEStatus != .success { - try await doBACAuthentication(tagReader : tagReader) + do { + trackingDelegate?.bacStarted() + + try await doBACAuthentication(tagReader : tagReader) + + trackingDelegate?.bacSucceeded() + } catch { + trackingDelegate?.bacFailed() + + throw error + } } // Now to read the datagroups @@ -295,8 +333,7 @@ extension PassportReader { func doBACAuthentication(tagReader : TagReader) async throws { self.currentlyReadingDataGroup = nil - - trackingDelegate?.nfcTagDetected() + Logger.passportReader.info( "Starting Basic Access Control (BAC)" ) self.passport.BACStatus = .failed From e1ff26287d9a82b228f04a06234ddeadfa922c30 Mon Sep 17 00:00:00 2001 From: Mika Hautz Date: Wed, 6 Nov 2024 16:02:08 +0100 Subject: [PATCH 5/5] Improve error handling --- Sources/NFCPassportReader/PassportReader.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/NFCPassportReader/PassportReader.swift b/Sources/NFCPassportReader/PassportReader.swift index 6b2e6d79..9c584437 100644 --- a/Sources/NFCPassportReader/PassportReader.swift +++ b/Sources/NFCPassportReader/PassportReader.swift @@ -230,13 +230,13 @@ extension PassportReader : NFCTagReaderSessionDelegate { } catch { Logger.passportReader.debug( "tagReaderSession:failed to connect to tag - \(error.localizedDescription)" ) - if let nfcError = error as? NFCReaderError { - // .readerTransceiveErrorTagResponseError is thrown when a "connection lost" scenario is forced by moving the phone away from the NFC chip - // .readerTransceiveErrorTagConnectionLost is never thrown for this scenario, but added for the sake of completeness - if nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagResponseError.rawValue || nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagConnectionLost.rawValue { - let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) - self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.ConnectionError) - } + // .readerTransceiveErrorTagResponseError is thrown when a "connection lost" scenario is forced by moving the phone away from the NFC chip + // .readerTransceiveErrorTagConnectionLost is never thrown for this scenario, but added for the sake of completeness + if let nfcError = error as? NFCReaderError, + nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagResponseError.rawValue || + nfcError.errorCode == NFCReaderError.readerTransceiveErrorTagConnectionLost.rawValue { + let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.ConnectionError) + self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.ConnectionError) } else { let errorMessage = NFCViewDisplayMessage.error(NFCPassportReaderError.Unknown(error)) self.invalidateSession(errorMessage: errorMessage, error: NFCPassportReaderError.Unknown(error))