From b4a5ad7f948a8763697d058fd64f975c28a2f523 Mon Sep 17 00:00:00 2001 From: Matthias Felix Date: Wed, 3 Mar 2021 08:54:18 +0100 Subject: [PATCH 1/5] Add parameter for international key exchange --- Sources/DP3TSDK/DP3TSDK.swift | 1 + Sources/DP3TSDK/Models/ApplicationDescriptor.swift | 5 ++++- Sources/DP3TSDK/Models/ExposeeListModel.swift | 8 ++++++-- Sources/DP3TSDK/Networking/Endpoints.swift | 9 ++++++++- Sources/DP3TSDK/Networking/ExposeeServiceClient.swift | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Sources/DP3TSDK/DP3TSDK.swift b/Sources/DP3TSDK/DP3TSDK.swift index 4805fbe2..862eace1 100644 --- a/Sources/DP3TSDK/DP3TSDK.swift +++ b/Sources/DP3TSDK/DP3TSDK.swift @@ -276,6 +276,7 @@ class DP3TSDK { mutableKeys.append(contentsOf: self.diagnosisKeysProvider.getFakeKeys(count: fakeKeyCount, startingFrom: startingFrom)) let model = ExposeeListModel(gaenKeys: mutableKeys, + withFederationGateway: self.applicationDescriptor.withFederationGateway, fake: isFakeRequest) self.service.addExposeeList(model, authentication: authentication) { [weak self] result in diff --git a/Sources/DP3TSDK/Models/ApplicationDescriptor.swift b/Sources/DP3TSDK/Models/ApplicationDescriptor.swift index e2ac20ae..1c20c0cb 100644 --- a/Sources/DP3TSDK/Models/ApplicationDescriptor.swift +++ b/Sources/DP3TSDK/Models/ApplicationDescriptor.swift @@ -12,11 +12,12 @@ import Foundation /// Model to describe the application configuration public struct ApplicationDescriptor { - public init(appId: String, bucketBaseUrl: URL, reportBaseUrl: URL, jwtPublicKey: Data? = nil, mode: Mode = .production) { + public init(appId: String, bucketBaseUrl: URL, reportBaseUrl: URL, jwtPublicKey: Data? = nil, withFederationGateway: Bool? = nil, mode: Mode = .production) { self.appId = appId self.bucketBaseUrl = bucketBaseUrl self.reportBaseUrl = reportBaseUrl self.jwtPublicKey = jwtPublicKey + self.withFederationGateway = withFederationGateway self.mode = mode } @@ -29,6 +30,8 @@ public struct ApplicationDescriptor { /// The JWT public key var jwtPublicKey: Data? + var withFederationGateway: Bool? + var mode: Mode = .production public enum Mode { diff --git a/Sources/DP3TSDK/Models/ExposeeListModel.swift b/Sources/DP3TSDK/Models/ExposeeListModel.swift index 046be40e..221b1bc3 100644 --- a/Sources/DP3TSDK/Models/ExposeeListModel.swift +++ b/Sources/DP3TSDK/Models/ExposeeListModel.swift @@ -23,17 +23,21 @@ struct ExposeeListModel: Encodable { /// Diagnosis keys let gaenKeys: [CodableDiagnosisKey] + let withFederationGateway: Bool? + let fake: Bool func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // Encode key try container.encode(gaenKeys, forKey: .gaenKeys) - + if let withFederationGateway = withFederationGateway { + try container.encode(withFederationGateway ? 1 : 0, forKey: .withFederationGateway) + } try container.encode(fake ? 1 : 0, forKey: .fake) } enum CodingKeys: CodingKey { - case gaenKeys, fake + case gaenKeys, withFederationGateway, fake } } diff --git a/Sources/DP3TSDK/Networking/Endpoints.swift b/Sources/DP3TSDK/Networking/Endpoints.swift index 9d86f09a..901c9c9a 100644 --- a/Sources/DP3TSDK/Networking/Endpoints.swift +++ b/Sources/DP3TSDK/Networking/Endpoints.swift @@ -33,7 +33,7 @@ struct ExposeeEndpoint { /// Get the URL for the exposed people endpoint for a given lastKeyBundleTag /// - Parameters: /// - lastKeyBundleTag: last published key tag if one is stored - func getExposee(lastKeyBundleTag: String?) -> URL { + func getExposee(lastKeyBundleTag: String?, withFederationGateway: Bool?) -> URL { let url = baseURLVersionned.appendingPathComponent("gaen") .appendingPathComponent("exposed") @@ -44,6 +44,13 @@ struct ExposeeEndpoint { ] } + if let withFederationGateway = withFederationGateway { + if urlComponents?.queryItems == nil { + urlComponents?.queryItems = [] + } + urlComponents?.queryItems?.append(URLQueryItem(name: "withFederationGateway", value: "\(withFederationGateway)")) + } + guard let finalUrl = urlComponents?.url else { fatalError("can't create URLComponents url") } diff --git a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift index ab4db933..e4a5b0ca 100644 --- a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift +++ b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift @@ -102,7 +102,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { /// - returns: array of objects or nil if they were already cached func getExposee(lastKeyBundleTag: String?, completion: @escaping (Result) -> Void) -> URLSessionDataTask { log.log("getExposeeSynchronously for lastPublishedKeyTag %{public}@", lastKeyBundleTag ?? "nil") - let url: URL = exposeeEndpoint.getExposee(lastKeyBundleTag: lastKeyBundleTag) + let url: URL = exposeeEndpoint.getExposee(lastKeyBundleTag: lastKeyBundleTag, withFederationGateway: descriptor.withFederationGateway) var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 60.0) request.setValue("application/zip", forHTTPHeaderField: "Accept") From c54d83203aa10ca98128070025a99a5867569a94 Mon Sep 17 00:00:00 2001 From: Matthias Felix Date: Thu, 4 Mar 2021 08:57:21 +0100 Subject: [PATCH 2/5] Make federationGateway an enum, add possibility to override value at runtime --- Sources/DP3TSDK/DP3TSDK.swift | 30 +++++++++++++++++-- Sources/DP3TSDK/DP3TTracing.swift | 7 +++-- .../Models/ApplicationDescriptor.swift | 5 +--- Sources/DP3TSDK/Networking/Endpoints.swift | 25 ++++++++++------ .../Networking/ExposeeServiceClient.swift | 9 ++++-- Sources/DP3TSDK/Storage/Defaults.swift | 11 +++++++ 6 files changed, 67 insertions(+), 20 deletions(-) diff --git a/Sources/DP3TSDK/DP3TSDK.swift b/Sources/DP3TSDK/DP3TSDK.swift index 862eace1..e10f945e 100644 --- a/Sources/DP3TSDK/DP3TSDK.swift +++ b/Sources/DP3TSDK/DP3TSDK.swift @@ -66,9 +66,11 @@ class DP3TSDK { /// - applicationDescriptor: information about the backend to use /// - urlSession: the url session to use for networking (app can set it to enable certificate pinning) /// - backgroundHandler: handler which gets called on background execution + /// - federationGateway: specifies whether keys should be shared with other countries convenience init(applicationDescriptor: ApplicationDescriptor, urlSession: URLSession, - backgroundHandler: DP3TBackgroundHandler?) { + backgroundHandler: DP3TBackgroundHandler?, + federationGateway: FederationGateway) { // reset keychain on first launch let defaults = Default.shared if defaults.isFirstLaunch { @@ -78,6 +80,8 @@ class DP3TSDK { defaults.reset() } + defaults.federationGateway = federationGateway + let exposureDayStorage = ExposureDayStorage() let manager = ENManager() @@ -85,7 +89,7 @@ class DP3TSDK { let matcher = ExposureNotificationMatcher(manager: manager, exposureDayStorage: exposureDayStorage) let diagnosisKeysProvider: DiagnosisKeysProvider = manager - let service = ExposeeServiceClient(descriptor: applicationDescriptor, urlSession: urlSession) + let service = ExposeeServiceClient(descriptor: applicationDescriptor, urlSession: urlSession, federationGateway: federationGateway) let synchronizer = KnownCasesSynchronizer(matcher: matcher, service: service, descriptor: applicationDescriptor) @@ -222,6 +226,16 @@ class DP3TSDK { return state } + var federationGateway: FederationGateway { + get { + return defaults.federationGateway + } + set { + defaults.federationGateway = newValue + service.federationGateway = newValue + } + } + /// tell the SDK that the user was exposed /// This will stop tracing /// - Parameters: @@ -275,8 +289,18 @@ class DP3TSDK { mutableKeys.append(contentsOf: self.diagnosisKeysProvider.getFakeKeys(count: fakeKeyCount, startingFrom: startingFrom)) + let withFederationGateway: Bool? + switch self.federationGateway { + case .yes: + withFederationGateway = true + case .no: + withFederationGateway = false + case .unspecified: + withFederationGateway = nil + } + let model = ExposeeListModel(gaenKeys: mutableKeys, - withFederationGateway: self.applicationDescriptor.withFederationGateway, + withFederationGateway: withFederationGateway, fake: isFakeRequest) self.service.addExposeeList(model, authentication: authentication) { [weak self] result in diff --git a/Sources/DP3TSDK/DP3TTracing.swift b/Sources/DP3TSDK/DP3TTracing.swift index ddaf0339..cc1768b3 100644 --- a/Sources/DP3TSDK/DP3TTracing.swift +++ b/Sources/DP3TSDK/DP3TTracing.swift @@ -64,15 +64,18 @@ public enum DP3TTracing { /// - enviroment: enviroment to use /// - urlSession: the url session to use for networking (can used to enable certificate pinning) /// - backgroundHandler: a delegate to perform background tasks + /// - federationGateway: specifies whether keys should be shared with other countries @available(iOS 12.5, *) public static func initialize(with applicationDescriptor: ApplicationDescriptor, urlSession: URLSession = .shared, - backgroundHandler: DP3TBackgroundHandler? = nil) { + backgroundHandler: DP3TBackgroundHandler? = nil, + federationGateway: FederationGateway = .unspecified) { precondition(Self.isOSCompatible, "Operating System is not compatible") precondition(instance == nil, "DP3TSDK already initialized") instance = DP3TSDK(applicationDescriptor: applicationDescriptor, urlSession: urlSession, - backgroundHandler: backgroundHandler) + backgroundHandler: backgroundHandler, + federationGateway: federationGateway) } @available(iOS 12.5, *) diff --git a/Sources/DP3TSDK/Models/ApplicationDescriptor.swift b/Sources/DP3TSDK/Models/ApplicationDescriptor.swift index 1c20c0cb..e2ac20ae 100644 --- a/Sources/DP3TSDK/Models/ApplicationDescriptor.swift +++ b/Sources/DP3TSDK/Models/ApplicationDescriptor.swift @@ -12,12 +12,11 @@ import Foundation /// Model to describe the application configuration public struct ApplicationDescriptor { - public init(appId: String, bucketBaseUrl: URL, reportBaseUrl: URL, jwtPublicKey: Data? = nil, withFederationGateway: Bool? = nil, mode: Mode = .production) { + public init(appId: String, bucketBaseUrl: URL, reportBaseUrl: URL, jwtPublicKey: Data? = nil, mode: Mode = .production) { self.appId = appId self.bucketBaseUrl = bucketBaseUrl self.reportBaseUrl = reportBaseUrl self.jwtPublicKey = jwtPublicKey - self.withFederationGateway = withFederationGateway self.mode = mode } @@ -30,8 +29,6 @@ public struct ApplicationDescriptor { /// The JWT public key var jwtPublicKey: Data? - var withFederationGateway: Bool? - var mode: Mode = .production public enum Mode { diff --git a/Sources/DP3TSDK/Networking/Endpoints.swift b/Sources/DP3TSDK/Networking/Endpoints.swift index 901c9c9a..8e7e8fff 100644 --- a/Sources/DP3TSDK/Networking/Endpoints.swift +++ b/Sources/DP3TSDK/Networking/Endpoints.swift @@ -33,22 +33,29 @@ struct ExposeeEndpoint { /// Get the URL for the exposed people endpoint for a given lastKeyBundleTag /// - Parameters: /// - lastKeyBundleTag: last published key tag if one is stored - func getExposee(lastKeyBundleTag: String?, withFederationGateway: Bool?) -> URL { + func getExposee(lastKeyBundleTag: String?, federationGateway: FederationGateway) -> URL { let url = baseURLVersionned.appendingPathComponent("gaen") .appendingPathComponent("exposed") var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) + + var queryItems: [URLQueryItem] = [] + if let lastKeyBundleTag = lastKeyBundleTag { - urlComponents?.queryItems = [ - URLQueryItem(name: "lastKeyBundleTag", value: lastKeyBundleTag) - ] + queryItems.append(URLQueryItem(name: "lastKeyBundleTag", value: lastKeyBundleTag)) + } + + switch federationGateway { + case .yes: + queryItems.append(URLQueryItem(name: "withFederationGateway", value: "true")) + case .no: + queryItems.append(URLQueryItem(name: "withFederationGateway", value: "false")) + case .unspecified: + break } - if let withFederationGateway = withFederationGateway { - if urlComponents?.queryItems == nil { - urlComponents?.queryItems = [] - } - urlComponents?.queryItems?.append(URLQueryItem(name: "withFederationGateway", value: "\(withFederationGateway)")) + if !queryItems.isEmpty { + urlComponents?.queryItems = queryItems } guard let finalUrl = urlComponents?.url else { diff --git a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift index e4a5b0ca..2b218f8b 100644 --- a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift +++ b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift @@ -23,6 +23,8 @@ protocol ExposeeServiceClientProtocol: class { var descriptor: ApplicationDescriptor { get } + var federationGateway: FederationGateway { get set } + /// Get all exposee for a known lastKeyBundleTag /// - Parameters: /// - since: last published key tag if one is stored @@ -52,6 +54,8 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { private let jwtVerifier: DP3TJWTVerifier? + var federationGateway: FederationGateway + private let log = Logger(ExposeeServiceClient.self, category: "exposeeServiceClient") /// The user agent to send with the requests @@ -66,7 +70,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { /// Initialize the client with a descriptor /// - Parameter descriptor: The descriptor to use - public init(descriptor: ApplicationDescriptor, urlSession: URLSession = .shared, urlCache: URLCache = .shared) { + public init(descriptor: ApplicationDescriptor, urlSession: URLSession = .shared, urlCache: URLCache = .shared, federationGateway: FederationGateway) { self.descriptor = descriptor self.urlSession = urlSession self.urlCache = urlCache @@ -77,6 +81,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { } else { jwtVerifier = nil } + self.federationGateway = federationGateway } func detectTimeshift(response: HTTPURLResponse) -> DP3TNetworkingError? { guard let date = response.date else { return nil } @@ -102,7 +107,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { /// - returns: array of objects or nil if they were already cached func getExposee(lastKeyBundleTag: String?, completion: @escaping (Result) -> Void) -> URLSessionDataTask { log.log("getExposeeSynchronously for lastPublishedKeyTag %{public}@", lastKeyBundleTag ?? "nil") - let url: URL = exposeeEndpoint.getExposee(lastKeyBundleTag: lastKeyBundleTag, withFederationGateway: descriptor.withFederationGateway) + let url: URL = exposeeEndpoint.getExposee(lastKeyBundleTag: lastKeyBundleTag, federationGateway: federationGateway) var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 60.0) request.setValue("application/zip", forHTTPHeaderField: "Accept") diff --git a/Sources/DP3TSDK/Storage/Defaults.swift b/Sources/DP3TSDK/Storage/Defaults.swift index 9caf9b9f..63b5bdc7 100644 --- a/Sources/DP3TSDK/Storage/Defaults.swift +++ b/Sources/DP3TSDK/Storage/Defaults.swift @@ -10,6 +10,12 @@ import Foundation +public enum FederationGateway: Int, Codable { + case yes + case no + case unspecified +} + protocol DefaultStorage { /// stores if this is the first launch of the SDK var isFirstLaunch: Bool { get set } @@ -27,6 +33,8 @@ protocol DefaultStorage { var exposureDetectionDates: [Date] { get set } + var federationGateway: FederationGateway { get set } + func reset() } @@ -53,6 +61,9 @@ class Default: DefaultStorage { @Persisted(userDefaultsKey: "org.dpppt.exposureDetectionDates", defaultValue: []) var exposureDetectionDates: [Date] + @Persisted(userDefaultsKey: "org.dpppt.federationGateway", defaultValue: .unspecified) + var federationGateway: FederationGateway + /// Parameters private func saveParameters(_ parameters: DP3TParameters) { From 2f26013c975158cf75ee8a7b373a5e607224f5c4 Mon Sep 17 00:00:00 2001 From: Matthias Felix Date: Thu, 4 Mar 2021 09:11:54 +0100 Subject: [PATCH 3/5] Fix tests, remove code smell --- Sources/DP3TSDK/DP3TSDK.swift | 8 ++++---- Tests/DP3TSDKTests/Mocks/MockService.swift | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Sources/DP3TSDK/DP3TSDK.swift b/Sources/DP3TSDK/DP3TSDK.swift index e10f945e..e31a6b8e 100644 --- a/Sources/DP3TSDK/DP3TSDK.swift +++ b/Sources/DP3TSDK/DP3TSDK.swift @@ -89,11 +89,11 @@ class DP3TSDK { let matcher = ExposureNotificationMatcher(manager: manager, exposureDayStorage: exposureDayStorage) let diagnosisKeysProvider: DiagnosisKeysProvider = manager - let service = ExposeeServiceClient(descriptor: applicationDescriptor, urlSession: urlSession, federationGateway: federationGateway) + let serviceClient = ExposeeServiceClient(descriptor: applicationDescriptor, urlSession: urlSession, federationGateway: federationGateway) - let synchronizer = KnownCasesSynchronizer(matcher: matcher, service: service, descriptor: applicationDescriptor) + let synchronizer = KnownCasesSynchronizer(matcher: matcher, service: serviceClient, descriptor: applicationDescriptor) - let backgroundTaskManager = DP3TBackgroundTaskManager(handler: backgroundHandler, keyProvider: manager, serviceClient: service, tracer: tracer, manager: manager) + let backgroundTaskManager = DP3TBackgroundTaskManager(handler: backgroundHandler, keyProvider: manager, serviceClient: serviceClient, tracer: tracer, manager: manager) self.init(applicationDescriptor: applicationDescriptor, urlSession: urlSession, @@ -101,7 +101,7 @@ class DP3TSDK { matcher: matcher, diagnosisKeysProvider: diagnosisKeysProvider, exposureDayStorage: exposureDayStorage, - service: service, + service: serviceClient, synchronizer: synchronizer, backgroundTaskManager: backgroundTaskManager, defaults: defaults) diff --git a/Tests/DP3TSDKTests/Mocks/MockService.swift b/Tests/DP3TSDKTests/Mocks/MockService.swift index 6d590b7b..43da9d1a 100644 --- a/Tests/DP3TSDKTests/Mocks/MockService.swift +++ b/Tests/DP3TSDKTests/Mocks/MockService.swift @@ -13,13 +13,14 @@ import Foundation class MockService: ExposeeServiceClientProtocol { - static var descriptor: ApplicationDescriptor = .init(appId: "org.dpppt", bucketBaseUrl: URL(string: "https://bucket.dpppt.org")!, reportBaseUrl: URL(string: "https://report.bucket.dpppt.org")!) var descriptor: ApplicationDescriptor { Self.descriptor } + var federationGateway: FederationGateway = .unspecified + var requests: [String?] = [] let session = MockSession(data: "Data".data(using: .utf8), urlResponse: nil, error: nil) let queue = DispatchQueue(label: "synchronous") From de2ca05be3e3e000d76fe9bfa2b41a3aea91c1c4 Mon Sep 17 00:00:00 2001 From: Matthias Felix Date: Thu, 4 Mar 2021 09:26:03 +0100 Subject: [PATCH 4/5] Fix tests --- Sources/DP3TSDK/Networking/ExposeeServiceClient.swift | 2 +- Tests/DP3TSDKTests/Mocks/MockDefaults.swift | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift index 2b218f8b..6b2b2b7e 100644 --- a/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift +++ b/Sources/DP3TSDK/Networking/ExposeeServiceClient.swift @@ -70,7 +70,7 @@ class ExposeeServiceClient: ExposeeServiceClientProtocol { /// Initialize the client with a descriptor /// - Parameter descriptor: The descriptor to use - public init(descriptor: ApplicationDescriptor, urlSession: URLSession = .shared, urlCache: URLCache = .shared, federationGateway: FederationGateway) { + public init(descriptor: ApplicationDescriptor, urlSession: URLSession = .shared, urlCache: URLCache = .shared, federationGateway: FederationGateway = .unspecified) { self.descriptor = descriptor self.urlSession = urlSession self.urlCache = urlCache diff --git a/Tests/DP3TSDKTests/Mocks/MockDefaults.swift b/Tests/DP3TSDKTests/Mocks/MockDefaults.swift index ab216e3f..28567986 100644 --- a/Tests/DP3TSDKTests/Mocks/MockDefaults.swift +++ b/Tests/DP3TSDKTests/Mocks/MockDefaults.swift @@ -24,6 +24,8 @@ class MockDefaults: DefaultStorage { var didMarkAsInfected: Bool = false + var federationGateway: FederationGateway = .unspecified + func reset() { exposureDetectionDates = [] lastKeyBundleTag = nil From b8bf03b508555d772fe3d76d93a556e3cbe31a8f Mon Sep 17 00:00:00 2001 From: Matthias Felix Date: Thu, 4 Mar 2021 09:40:14 +0100 Subject: [PATCH 5/5] Update Readme and Changelog --- CHANGELOG.md | 5 ++++- README.md | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c4294d..483b6a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # Changelog for DP3T-SDK iOS +## Next version +- Add support for international key exchange with parameter 'federationGateway' + ## Version 2.1.0 (21.12.2020) -- Add support for iOS 12.5 +- Add support for iOS 12.5 - Fix timeshift detection ## Version 2.0.0 (29.10.2020) diff --git a/README.md b/README.md index 1f757918..6280b5ab 100644 --- a/README.md +++ b/README.md @@ -45,16 +45,17 @@ Included in this repository is a Calibration App that can run, debug and test th ### Initialization Name | Description | Function Name ---- | ----------- | ------------- -init | Initializes the SDK and configures it | `initialize(applicationDescriptor:urlSession:backgroundHandler)` +init | Initializes the SDK and configures it | `initialize(applicationDescriptor:urlSession:backgroundHandler:federationGateway)` -### Methods -Name | Description | Function Name +### Methods & Properties +Name | Description | Function/Variable Name ---- | ----------- | ------------- startTracing | Starts EN tracing | `func startTracing(completionHandler:)` stopTracing | Stops EN tracing | `func stopTracing(completionHandler:)` sync | Pro-actively triggers sync with backend to refresh exposed list | `func sync(callback:)` status | Returns a TracingState-Object describing the current state. This contains:
- `numberOfHandshakes` : `Int`
- `trackingState` : `TrackingState`
- `lastSync` : `Date`
- `infectionStatus`:`InfectionStatus`
- `backgroundRefreshState`:`UIBackgroundRefreshStatus ` | `func status(callback:)` -iWasExposed | This method must be called upon positive test. | `func iWasExposed(onset:authentication:isFakeRequest:callback:)` +iWasExposed | This method must be called upon positive test. | `func iWasExposed(onset:authentication:isFakeRequest:callback:)` +federationGateway | Specifies whether keys should be exchanged with other compatible countries. Possible values are 'yes', 'no', 'unspecified' (default) | `var federationGateway` reset | Removes all SDK related data | `func reset()`