From eb1a6f6b461a36984e446bff2741e5c52a4113da Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 10:34:26 +0200 Subject: [PATCH 1/6] Show on both dashboards Signed-off-by: Ian Dundas --- .../Interface/Holder/Dashboard/HolderDashboardViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift b/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift index 959a0120e..95285bc73 100644 --- a/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift +++ b/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift @@ -294,7 +294,7 @@ final class HolderDashboardViewModel: Logging { ] } - if state.deviceHasClockDeviation && validityRegion == .domestic && !regionFilteredMyQRCards.isEmpty { + if state.deviceHasClockDeviation && !allQRCards.isEmpty { viewControllerCards += [ .deviceHasClockDeviation(message: L.holderDashboardClockDeviationDetectedMessage(), didTapMoreInfo: { coordinatorDelegate.userWishesMoreInfoAboutClockDeviation() From f49965614aac18d496ba2a3000391e7841a0c1f8 Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 10:25:14 +0200 Subject: [PATCH 2/6] Draft fix for clock deviation Signed-off-by: Ian Dundas --- .../Services/ClockDeviationManager.swift | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift b/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift index ab35dceca..67d509f30 100644 --- a/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift +++ b/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift @@ -13,7 +13,7 @@ protocol ClockDeviationManaging: AnyObject { init() func update(serverHeaderDate: String) - func update(serverResponseDateTime: Date, localResponseDatetime: Date, localResponseSystemUptime: TimeInterval) + func update(serverResponseDateTime: Date, localResponseDateTime: Date, localResponseSystemUptime: __darwin_time_t) func appendDeviationChangeObserver(_ observer: @escaping (Bool) -> Void) -> ClockDeviationManager.ObserverToken func removeDeviationChangeObserver(token: ClockDeviationManager.ObserverToken) @@ -24,31 +24,32 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { var hasSignificantDeviation: Bool? { guard let serverResponseDateTime = serverResponseDateTime, - let localResponseDatetime = localResponseDatetime, + let localResponseDatetime = localResponseDateTime, let localResponseSystemUptime = localResponseSystemUptime, let clockDeviationThresholdSeconds = clockDeviationThresholdSeconds else { return nil } let result = ClockDeviationManager.hasSignificantDeviation( serverResponseDateTime: serverResponseDateTime, - localResponseDatetime: localResponseDatetime, - clockDeviationThresholdSeconds: clockDeviationThresholdSeconds, - localSystemUptime: localResponseSystemUptime, - systemUptime: currentSystemUptime(), - now: now() + localResponseDateTime: localResponseDatetime, + localResponseSystemUptime: localResponseSystemUptime, + currentDate: now(), + currentSystemUptime: currentSystemUptime(), + clockDeviationThresholdSeconds: clockDeviationThresholdSeconds ) + return result } private var serverResponseDateTime: Date? - private var localResponseDatetime: Date? - private var localResponseSystemUptime: TimeInterval? + private var localResponseDateTime: Date? + private var localResponseSystemUptime: __darwin_time_t? private var clockDeviationThresholdSeconds: Double? { remoteConfigManager.getConfiguration().clockDeviationThresholdSeconds.map { Double($0) } } private let remoteConfigManager: RemoteConfigManaging - private let currentSystemUptime: () -> TimeInterval + private let currentSystemUptime: () -> __darwin_time_t private let now: () -> Date private var deviationChangeObservers = [ObserverToken: (Bool) -> Void]() private lazy var serverHeaderDateFormatter: DateFormatter = { @@ -61,14 +62,14 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { required convenience init() { self.init( remoteConfigManager: Services.remoteConfigManager, - currentSystemUptime: { ProcessInfo.processInfo.systemUptime }, + currentSystemUptime: { ClockDeviationManager.currentSystemUptime() }, now: { Date() } ) } required init( remoteConfigManager: RemoteConfigManaging = Services.remoteConfigManager, - currentSystemUptime: @escaping () -> TimeInterval = { ProcessInfo.processInfo.systemUptime }, + currentSystemUptime: @escaping () -> __darwin_time_t = { ClockDeviationManager.currentSystemUptime() }, now: @escaping () -> Date = { Date() } ) { self.remoteConfigManager = remoteConfigManager @@ -96,14 +97,14 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { update( serverResponseDateTime: serverDate, - localResponseDatetime: now(), + localResponseDateTime: now(), localResponseSystemUptime: currentSystemUptime() ) } - func update(serverResponseDateTime: Date, localResponseDatetime: Date, localResponseSystemUptime: TimeInterval) { + func update(serverResponseDateTime: Date, localResponseDateTime: Date, localResponseSystemUptime: __darwin_time_t) { self.serverResponseDateTime = serverResponseDateTime - self.localResponseDatetime = localResponseDatetime + self.localResponseDateTime = localResponseDateTime self.localResponseSystemUptime = localResponseSystemUptime notifyObservers() } @@ -138,19 +139,33 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { /// - now: the current local time private static func hasSignificantDeviation( serverResponseDateTime: Date, - localResponseDatetime: Date, - clockDeviationThresholdSeconds: Double, - localSystemUptime: TimeInterval, - systemUptime: TimeInterval, - now: Date = Date() + localResponseDateTime: Date, + localResponseSystemUptime: __darwin_time_t, + currentDate: Date = Date(), + currentSystemUptime: __darwin_time_t, + clockDeviationThresholdSeconds: Double ) -> Bool { - let responseSystemStartDatetime = localResponseDatetime.timeIntervalSince1970 - localSystemUptime - let currentSystemStartDateTime = now.timeIntervalSince1970 - systemUptime + let responseSystemStartDatetime = localResponseDateTime.timeIntervalSince1970 - TimeInterval(localResponseSystemUptime) + let currentSystemStartDateTime = currentDate.timeIntervalSince1970 - TimeInterval(currentSystemUptime) let systemUptimeDelta = currentSystemStartDateTime - responseSystemStartDatetime - let responseTimeDelta = localResponseDatetime.timeIntervalSince1970 - serverResponseDateTime.timeIntervalSince1970 + let responseTimeDelta = localResponseDateTime.timeIntervalSince1970 - serverResponseDateTime.timeIntervalSince1970 let hasDeviation = abs(responseTimeDelta + systemUptimeDelta) >= clockDeviationThresholdSeconds return hasDeviation } + + private static func currentSystemUptime() -> __darwin_time_t { + + var uptime = timespec() + + // CLOCK_MONOTONIC represents the absolute elapsed wall-clock time since some arbitrary, + // fixed point in the past. It isn't affected by changes in the system time-of-day clock. + guard 0 == clock_gettime(CLOCK_MONOTONIC, &uptime) else { + // TODO: remove + fatalError("Could not execute clock_gettime, errno: \(errno)") + } + + return uptime.tv_sec + } } From a6aee4bcb0c4a75e504e7f9b8faa7b08f8155a9c Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 14:33:21 +0200 Subject: [PATCH 3/6] Set the deviceHasClockDeviation on dashboard screen load Signed-off-by: Ian Dundas --- .../Interface/Holder/Dashboard/HolderDashboardViewModel.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift b/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift index 95285bc73..31f682268 100644 --- a/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift +++ b/Sources/CTR/Interface/Holder/Dashboard/HolderDashboardViewModel.swift @@ -115,7 +115,8 @@ final class HolderDashboardViewModel: Logging { myQRCards: [], expiredGreenCards: [], showCreateCard: true, - isRefreshingStrippen: false + isRefreshingStrippen: false, + deviceHasClockDeviation: Services.clockDeviationManager.hasSignificantDeviation ?? false ) self.datasource.didUpdate = { [weak self] (qrCardDataItems: [MyQRCard], expiredGreenCards: [ExpiredQR]) in From a47402ef97a7b8ac85e2defaa475333e1ae89e3b Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 15:16:58 +0200 Subject: [PATCH 4/6] Remove excess linebreaks Signed-off-by: Ian Dundas --- Localizations/CoronaCheck holder/en/Localizable.strings | 2 +- Localizations/CoronaCheck holder/nl/Localizable.strings | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Localizations/CoronaCheck holder/en/Localizable.strings b/Localizations/CoronaCheck holder/en/Localizable.strings index 3048f21a3..f8ab01ee2 100644 --- a/Localizations/CoronaCheck holder/en/Localizable.strings +++ b/Localizations/CoronaCheck holder/en/Localizable.strings @@ -349,7 +349,7 @@ "holder.dashboard.empty.domestic.title" = "Find your Dutch certificate here later"; "holder.dashboard.empty.domestic.message" = "

You can add a certificate if you're vaccinated, if you've had corona or by taking a test at an affiliated test location. The app generates a certificate for the Netherlands and one for other countries.

"; "holder.dashboard.empty.international.title" = "Find your international certificate here later"; -"holder.dashboard.empty.international.message" = "

Are you abroad, or planning to cross the border? Then always use your international certificate. Please check before leaving which certificate you need.


Which certificate is valid where I’m heading?

"; +"holder.dashboard.empty.international.message" = "

Are you abroad, or planning to cross the border? Then always use your international certificate. Please check before leaving which certificate you need.

Which certificate is valid where I’m heading?

"; /* MARK: - Holder Enlarged */ "holder.enlarged.screenshot.title" = "A screenshot is not a valid entrance ticket."; "holder.enlarged.screenshot.message" = "A screenshot causes issues when scanning. You can only use the QR code in the app as a valid entrance ticket."; diff --git a/Localizations/CoronaCheck holder/nl/Localizable.strings b/Localizations/CoronaCheck holder/nl/Localizable.strings index fd5482eb3..1491c6023 100644 --- a/Localizations/CoronaCheck holder/nl/Localizable.strings +++ b/Localizations/CoronaCheck holder/nl/Localizable.strings @@ -311,7 +311,7 @@ /* MARK: - Holder Dashboard */ "holder.dashboard.title" = "Mijn bewijzen"; "holder.dashboard.intro.domestic" = "Laat de QR-code en je identiteitsbewijs zien bij de ingang van de locatie die je bezoekt."; -"holder.dashboard.intro.international" = "

Ben je in het buitenland of ga je de grens over? Gebruik dan altijd de internationale QR-code hieronder. Controleer voor vertrek welk bewijs je nodig hebt.


Is mijn bewijs geldig op mijn bestemming?

"; +"holder.dashboard.intro.international" = "

Ben je in het buitenland of ga je de grens over? Gebruik dan altijd de internationale QR-code hieronder. Controleer voor vertrek welk bewijs je nodig hebt.

Is mijn bewijs geldig op mijn bestemming?

"; "holder.dashboard.qr.expired" = "Je QR-code is verlopen."; "holder.dashboard.qr.hour" = "uur"; "holder.dashboard.qr.minute" = "min"; @@ -349,7 +349,7 @@ "holder.dashboard.empty.domestic.title" = "Hier komt jouw Nederlandse bewijs"; "holder.dashboard.empty.domestic.message" = "

Je kunt een bewijs toevoegen als je bent gevaccineerd of hersteld. Of als je bent getest bij een aangesloten testlocatie. De app maakt een Nederlands en een internationaal bewijs.

"; "holder.dashboard.empty.international.title" = "Hier komt jouw internationale bewijs"; -"holder.dashboard.empty.international.message" = "

Ben je in het buitenland of ga je de grens over? Gebruik dan altijd jouw internationale bewijs. Controleer voor vertrek welk bewijs je nodig hebt.


Welk bewijs is geldig op mijn bestemming?

"; +"holder.dashboard.empty.international.message" = "

Ben je in het buitenland of ga je de grens over? Gebruik dan altijd jouw internationale bewijs. Controleer voor vertrek welk bewijs je nodig hebt.

Welk bewijs is geldig op mijn bestemming?

"; /* MARK: - Holder Enlarged */ "holder.enlarged.screenshot.title" = "Een schermafbeelding is geen geldig toegangsbewijs"; "holder.enlarged.screenshot.message" = "Een schermafbeelding zorgt voor problemen bij het scannen. Alleen de QR-code in de app is een geldig toegangsbewijs."; From 0a2ff94d452fe61eb4f3bf412ef9f4f09e938591 Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 15:39:01 +0200 Subject: [PATCH 5/6] Remove fatalError Signed-off-by: Ian Dundas --- .../Services/ClockDeviationManager.swift | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift b/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift index 67d509f30..d3f4f6571 100644 --- a/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift +++ b/Sources/CTR/Infrastructure/Services/ClockDeviationManager.swift @@ -26,7 +26,8 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { guard let serverResponseDateTime = serverResponseDateTime, let localResponseDatetime = localResponseDateTime, let localResponseSystemUptime = localResponseSystemUptime, - let clockDeviationThresholdSeconds = clockDeviationThresholdSeconds + let clockDeviationThresholdSeconds = clockDeviationThresholdSeconds, + let systemUptime = currentSystemUptime() else { return nil } let result = ClockDeviationManager.hasSignificantDeviation( @@ -34,7 +35,7 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { localResponseDateTime: localResponseDatetime, localResponseSystemUptime: localResponseSystemUptime, currentDate: now(), - currentSystemUptime: currentSystemUptime(), + currentSystemUptime: systemUptime, clockDeviationThresholdSeconds: clockDeviationThresholdSeconds ) @@ -49,7 +50,7 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { remoteConfigManager.getConfiguration().clockDeviationThresholdSeconds.map { Double($0) } } private let remoteConfigManager: RemoteConfigManaging - private let currentSystemUptime: () -> __darwin_time_t + private let currentSystemUptime: () -> __darwin_time_t? private let now: () -> Date private var deviationChangeObservers = [ObserverToken: (Bool) -> Void]() private lazy var serverHeaderDateFormatter: DateFormatter = { @@ -69,7 +70,7 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { required init( remoteConfigManager: RemoteConfigManaging = Services.remoteConfigManager, - currentSystemUptime: @escaping () -> __darwin_time_t = { ClockDeviationManager.currentSystemUptime() }, + currentSystemUptime: @escaping () -> __darwin_time_t? = { ClockDeviationManager.currentSystemUptime() }, now: @escaping () -> Date = { Date() } ) { self.remoteConfigManager = remoteConfigManager @@ -93,12 +94,14 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { /// Update using the Server Response Header string /// e.g. "Sat, 07 Aug 2021 12:12:57 GMT" func update(serverHeaderDate: String) { - guard let serverDate = serverHeaderDateFormatter.date(from: serverHeaderDate) else { return } + guard let serverDate = serverHeaderDateFormatter.date(from: serverHeaderDate), + let systemUptime = currentSystemUptime() + else { return } update( serverResponseDateTime: serverDate, localResponseDateTime: now(), - localResponseSystemUptime: currentSystemUptime() + localResponseSystemUptime: systemUptime ) } @@ -155,15 +158,16 @@ class ClockDeviationManager: ClockDeviationManaging, Logging { return hasDeviation } - private static func currentSystemUptime() -> __darwin_time_t { + private static func currentSystemUptime() -> __darwin_time_t? { var uptime = timespec() - // CLOCK_MONOTONIC represents the absolute elapsed wall-clock time since some arbitrary, + // `CLOCK_MONOTONIC` represents the absolute elapsed wall-clock time since some arbitrary, // fixed point in the past. It isn't affected by changes in the system time-of-day clock. - guard 0 == clock_gettime(CLOCK_MONOTONIC, &uptime) else { - // TODO: remove - fatalError("Could not execute clock_gettime, errno: \(errno)") + + // Check response is 0 else there was an error: + guard clock_gettime(CLOCK_MONOTONIC, &uptime) == 0 else { + return nil } return uptime.tv_sec From 4ad3a0d3ae550e9cb77ec082313d83742085b2af Mon Sep 17 00:00:00 2001 From: Ian Dundas Date: Thu, 12 Aug 2021 15:59:20 +0200 Subject: [PATCH 6/6] Fix test compiling Signed-off-by: Ian Dundas --- .../Infrastrucure/Services/ClockDeviationManagerTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CTRTests/Infrastrucure/Services/ClockDeviationManagerTests.swift b/CTRTests/Infrastrucure/Services/ClockDeviationManagerTests.swift index b4f825737..b230cbe1a 100644 --- a/CTRTests/Infrastrucure/Services/ClockDeviationManagerTests.swift +++ b/CTRTests/Infrastrucure/Services/ClockDeviationManagerTests.swift @@ -23,7 +23,7 @@ class ClockDeviationManagerTests: XCTestCase { sut = ClockDeviationManager( remoteConfigManager: remoteConfigManagerSpy, - currentSystemUptime: { 1 * hour }, + currentSystemUptime: { 1 * 3600 }, now: { now } ) }