diff --git a/CHANGELOG.md b/CHANGELOG.md index 3524e7d9..90f6ff8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog for DP3T-SDK iOS +## Version 2.3.0 (30.04.2021) +- expose oldest shared keydate when calling iWasExposed + ## Version 2.2.0 (25.03.2021) - Add support for international key exchange with parameter 'federationGateway' diff --git a/DP3TSDK.podspec b/DP3TSDK.podspec index b35b00ee..0be4d3cf 100644 --- a/DP3TSDK.podspec +++ b/DP3TSDK.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |spec| spec.name = "DP3TSDK" - spec.version = ENV['LIB_VERSION'] || '2.2.0' + spec.version = ENV['LIB_VERSION'] || '2.3.0' spec.summary = "Open protocol for COVID-19 proximity tracing using Bluetooth Low Energy on mobile devices" spec.description = <<-DESC diff --git a/README.md b/README.md index a6401975..ff6081b0 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ DP3T-SDK is available through [Cocoapods](https://cocoapods.org/) ```ruby - pod 'DP3TSDK', => '2.2.0' + pod 'DP3TSDK', => '2.3.0' ``` diff --git a/Sources/DP3TSDK/DP3TSDK.swift b/Sources/DP3TSDK/DP3TSDK.swift index e31a6b8e..37dfe312 100644 --- a/Sources/DP3TSDK/DP3TSDK.swift +++ b/Sources/DP3TSDK/DP3TSDK.swift @@ -246,7 +246,7 @@ class DP3TSDK { func iWasExposed(onset: Date, authentication: ExposeeAuthMethod, isFakeRequest: Bool = false, - callback: @escaping (Result) -> Void) { + callback: @escaping (Result) -> Void) { log.trace() if !isFakeRequest, case .infected = state.infectionStatus { @@ -299,6 +299,11 @@ class DP3TSDK { withFederationGateway = nil } + var oldestNonFakeKeyDate: Date? = nil + if !isFakeRequest { + oldestNonFakeKeyDate = Date(timeIntervalSince1970: Double(oldestRollingStartNumber) * 10 * .minute) + } + let model = ExposeeListModel(gaenKeys: mutableKeys, withFederationGateway: withFederationGateway, fake: isFakeRequest) @@ -313,7 +318,7 @@ class DP3TSDK { self.tracer.setEnabled(false, completionHandler: nil) } - callback(.success(())) + callback(.success(.init(oldestKeyDate: oldestNonFakeKeyDate))) case let .failure(error): callback(.failure(.networkingError(error: error))) } diff --git a/Sources/DP3TSDK/DP3TTracing.swift b/Sources/DP3TSDK/DP3TTracing.swift index c8f0c5bf..30fff9f5 100644 --- a/Sources/DP3TSDK/DP3TTracing.swift +++ b/Sources/DP3TSDK/DP3TTracing.swift @@ -29,7 +29,7 @@ private var instance: DP3TSDK! /// DP3TTracing public enum DP3TTracing { /// The current version of the SDK - public static let frameworkVersion: String = "2.2.0" + public static let frameworkVersion: String = "2.3.0" /// sets global parameter values which are used throughout the sdk public static var parameters: DP3TParameters { @@ -135,6 +135,11 @@ public enum DP3TTracing { return instance.status } + + public struct IWasExposedResult { + public let oldestKeyDate: Date? + } + /// tell the SDK that the user was exposed /// - Parameters: /// - onset: Start date of the exposure @@ -145,7 +150,7 @@ public enum DP3TTracing { public static func iWasExposed(onset: Date, authentication: ExposeeAuthMethod, isFakeRequest: Bool = false, - callback: @escaping (Result) -> Void) { + callback: @escaping (Result) -> Void) { instancePrecondition() instance.iWasExposed(onset: onset, authentication: authentication, diff --git a/Sources/DP3TSDK/Models/ExposeeListModel.swift b/Sources/DP3TSDK/Models/ExposeeListModel.swift index 221b1bc3..509c483f 100644 --- a/Sources/DP3TSDK/Models/ExposeeListModel.swift +++ b/Sources/DP3TSDK/Models/ExposeeListModel.swift @@ -18,6 +18,12 @@ struct CodableDiagnosisKey: Codable, Equatable { let fake: UInt8 } +extension CodableDiagnosisKey { + var date: Date { + Date(timeIntervalSince1970: TimeInterval(rollingStartNumber) * TimeInterval.minute * 10) + } +} + /// Model of the exposed person struct ExposeeListModel: Encodable { /// Diagnosis keys diff --git a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift index 6b2b2b7e..79a67519 100644 --- a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift +++ b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift @@ -54,7 +54,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { private let jwtVerifier: DP3TJWTVerifier? - var federationGateway: FederationGateway + internal var federationGateway: FederationGateway private let log = Logger(ExposeeServiceClient.self, category: "exposeeServiceClient") diff --git a/Tests/DP3TSDKTests/DP3TSDKTests.swift b/Tests/DP3TSDKTests/DP3TSDKTests.swift index 3da11e73..b91292b0 100644 --- a/Tests/DP3TSDKTests/DP3TSDKTests.swift +++ b/Tests/DP3TSDKTests/DP3TSDKTests.swift @@ -26,6 +26,7 @@ private class MockKeyProvider: DiagnosisKeysProvider { } +@available(iOS 12.5, *) class DP3TSDKTests: XCTestCase { fileprivate var keychain: MockKeychain! @@ -95,8 +96,18 @@ class DP3TSDKTests: XCTestCase { XCTAssertEqual(sdk.status.infectionStatus, .healthy) let exp = expectation(description: "infected") - keyProvider.keys = [ .init(keyData: Data(count: 16), rollingPeriod: 144, rollingStartNumber: DayDate().period, transmissionRiskLevel: 0, fake: 0) ] + let oldestDate = Date(timeIntervalSinceNow: -.day * 5) + keyProvider.keys = [ + .init(keyData: Data(count: 16), rollingPeriod: 144, rollingStartNumber: DayDate(date: oldestDate.addingTimeInterval(.day)).period, transmissionRiskLevel: 0, fake: 0), + .init(keyData: Data(count: 16), rollingPeriod: 144, rollingStartNumber: DayDate(date: oldestDate).period, transmissionRiskLevel: 0, fake: 0), + .init(keyData: Data(count: 16), rollingPeriod: 144, rollingStartNumber: DayDate(date: oldestDate.addingTimeInterval(.day * 2)).period, transmissionRiskLevel: 0, fake: 0), + ] sdk.iWasExposed(onset: .init(timeIntervalSinceNow: -.day), authentication: .none) { (result) in + if case let Result.success(wrapper) = result { + XCTAssertEqual(wrapper.oldestKeyDate, DayDate(date: oldestDate).dayMin) + } else { + XCTFail() + } exp.fulfill() } wait(for: [exp], timeout: 0.1) @@ -107,8 +118,8 @@ class DP3TSDKTests: XCTestCase { let rollingStartNumbers = Set(model!.gaenKeys.map(\.rollingStartNumber)) XCTAssertEqual(rollingStartNumbers.count, model!.gaenKeys.count) var runningDate: Date? - for key in model!.gaenKeys { - let date = Date(timeIntervalSince1970: Double(key.rollingStartNumber) * 10 * .minute) + for key in model!.gaenKeys.sorted(by: { $0.date > $1.date }) { + let date = key.date guard runningDate != nil else { runningDate = date continue diff --git a/Tests/DP3TSDKTests/DiagnosisKeysProviderTests.swift b/Tests/DP3TSDKTests/DiagnosisKeysProviderTests.swift index 20971e04..6cce16f0 100644 --- a/Tests/DP3TSDKTests/DiagnosisKeysProviderTests.swift +++ b/Tests/DP3TSDKTests/DiagnosisKeysProviderTests.swift @@ -13,6 +13,7 @@ import Foundation import XCTest import ExposureNotification +@available(iOS 12.5, *) class DiagnosisKeysProviderTests: XCTestCase { var manager: MockENManager! @@ -81,6 +82,7 @@ class DiagnosisKeysProviderTests: XCTestCase { } +@available(iOS 12.5, *) extension ENTemporaryExposureKey { static func initialize(data: Data = Data(capacity: 16), rollingPeriod: ENIntervalNumber = UInt32(TimeInterval.day / (.minute * 10)), diff --git a/Tests/DP3TSDKTests/ExposureNotificationMatcherTests.swift b/Tests/DP3TSDKTests/ExposureNotificationMatcherTests.swift index 9d81fc8e..3b653ee6 100644 --- a/Tests/DP3TSDKTests/ExposureNotificationMatcherTests.swift +++ b/Tests/DP3TSDKTests/ExposureNotificationMatcherTests.swift @@ -15,6 +15,7 @@ import Foundation import XCTest import ZIPFoundation +@available(iOS 12.5, *) final class ExposureNotificationMatcherTests: XCTestCase { var keychain = MockKeychain() diff --git a/Tests/DP3TSDKTests/ExposureNotificationTracerTests.swift b/Tests/DP3TSDKTests/ExposureNotificationTracerTests.swift index 88248b5b..dbda23cf 100644 --- a/Tests/DP3TSDKTests/ExposureNotificationTracerTests.swift +++ b/Tests/DP3TSDKTests/ExposureNotificationTracerTests.swift @@ -11,6 +11,7 @@ @testable import DP3TSDK import XCTest +@available(iOS 12.5, *) class ExposureNotificationTracerTests: XCTestCase { var manager: MockENManager! diff --git a/Tests/DP3TSDKTests/ExposureWindowTests.swift b/Tests/DP3TSDKTests/ExposureWindowTests.swift index d1bc391c..02463984 100644 --- a/Tests/DP3TSDKTests/ExposureWindowTests.swift +++ b/Tests/DP3TSDKTests/ExposureWindowTests.swift @@ -13,6 +13,7 @@ import XCTest import ExposureNotification +@available(iOS 12.5, *) class ExposureWindowTests: XCTestCase { func testDayGroupingSingle(){ var windows: [MockWindow] = [] diff --git a/Tests/DP3TSDKTests/Mocks/MockENManager.swift b/Tests/DP3TSDKTests/Mocks/MockENManager.swift index f96f8032..a6fff1d5 100644 --- a/Tests/DP3TSDKTests/Mocks/MockENManager.swift +++ b/Tests/DP3TSDKTests/Mocks/MockENManager.swift @@ -12,6 +12,7 @@ import Foundation import ExposureNotification +@available(iOS 12.5, *) class MockENManager: ENManager { var activateCallbacks: [ENErrorHandler] = [] @@ -108,6 +109,7 @@ class MockENManager: ENManager { } } +@available(iOS 12.5, *) class MockSummary: ENExposureDetectionSummary { override var attenuationDurations: [NSNumber] { get { diff --git a/Tests/DP3TSDKTests/Mocks/MockScanInstance.swift b/Tests/DP3TSDKTests/Mocks/MockScanInstance.swift index c1a2aa42..f4018f84 100644 --- a/Tests/DP3TSDKTests/Mocks/MockScanInstance.swift +++ b/Tests/DP3TSDKTests/Mocks/MockScanInstance.swift @@ -11,6 +11,7 @@ import Foundation import ExposureNotification +@available(iOS 12.5, *) class MockScanInstance: ENScanInstance { private var internalTypicalAttenuation: ENAttenuation diff --git a/Tests/DP3TSDKTests/Mocks/MockWindow.swift b/Tests/DP3TSDKTests/Mocks/MockWindow.swift index e566b35c..a10ef186 100644 --- a/Tests/DP3TSDKTests/Mocks/MockWindow.swift +++ b/Tests/DP3TSDKTests/Mocks/MockWindow.swift @@ -11,6 +11,7 @@ import Foundation import ExposureNotification +@available(iOS 12.5, *) class MockWindow: ENExposureWindow { private var internalDate: Date private var internalScanInstances: [ENScanInstance]