dp-3t / dp3t-sdk-ios Goto Github PK
View Code? Open in Web Editor NEWThe DP3T-SDK for iOS
License: Mozilla Public License 2.0
The DP3T-SDK for iOS
License: Mozilla Public License 2.0
Device info: iPhone 11 Pro. iOS 13.5.1
According to the FAQ the impact the application has on battery life should be relatively low.
Having installed the app last week I have noticed my battery requires much more frequent charging. I had a look at the battery statistics this morning:
Over a 24hr period the level of my battery fell from approx 75% to approx 25%. According to the battery stats 80% of that was the health app logging data from the SwissCovid app. That seems rather excessive.
Is there an issue here, or is this expected behaviour?
Hi, can you please deploy/push the new .podspec to cocoapods to include the ProtoBuf and SwiftJWT dependency please?
Thanks
While the commit history includes MR #188, the changes of that commit were not merged to master with #192. You can check by doing git diff 4ab9c2044e47a632fdbf4f48c7d4a7b3cd9345a0..master
. This probably has something to do with the mishap that the first MR was merged to master and reverted. Finally a new MR was made to target develop.
Could we do a version 1.1.1 that will include the changes?
According to the JWTVerifier source code, only a
[...] UTF8 encoded PEM public key, with a "BEGIN PUBLIC KEY" header
is supported. This has lead to confusion (SwissCovid/swisscovid-app-ios#352) since Android allows the use of a x509-Certificate directly.
Either iOS abstracts the public key in a type alias as well, and provides the corresponding constructors, or specifies the format needed here
Further, the documentation needs to be updated.
How the notification sending work ? do we need to upload the certificate somewhere ?
The DP3TCryptoModule.swift
would be much easier to read if it had references to the whitepaper in it.
I originally left this issue in the CH app git, but I think it's an issue in the backend code (if it's an issue), hence I repeat it here so it's not missed (sorry for the initially wrong posting)
In DP3TSDK/Networking/ExposeeServiceClient.swift
:
/// The endpoint for getting exposee
private let exposeeEndpoint: ExposeeEndpoint
/// The endpoint for adding and removing exposee
private let managingExposeeEndpoint: ManagingExposeeEndpoint
so I guess exposeeEndpoint
is used to download keys (GET /v1/exposed/
), and managingExposeeEndpoint
would be used to report keys (POST /v1/exposed/
). In many cases, these would end at the same endpoint, but they can also differ (DDOS protection etc). This assumption I think is supported by the later code:
/// Adds an exposee
/// - Parameters:
/// - exposee: The exposee to add
/// - completion: The completion block
/// - authentication: The authentication to use for the request
func addExposee(_ exposee: ExposeeModel, authentication: ExposeeAuthMethod, completion: @escaping (Result<Void, DP3TTracingError>) -> Void) {
// addExposee endpoint
let url = managingExposeeEndpoint.addExposee()
guard let payload = try? JSONEncoder().encode(exposee) else {
completion(.failure(.networkingError(error: nil)))
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
which clearly is a POST to managingExposeeEndpoint
and so should go to the report URL. The other code is
/// Get all exposee for a known day synchronously
/// - Parameters:
/// - batchTimestamp: The batch timestamp
/// - completion: The completion block
/// - returns: array of objects or nil if they were already cached
func getExposeeSynchronously(batchTimestamp: Date) -> Result<[KnownCaseModel]?, DP3TTracingError> {
let url = exposeeEndpoint.getExposee(batchTimestamp: batchTimestamp)
var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 60.0)
request.setValue("application/x-protobuf", forHTTPHeaderField: "Accept")
which is the GET request (using application/x-protobuf
as binary download format).
However, in the actual assignments, we see:
exposeeEndpoint = ExposeeEndpoint(baseURL: descriptor.reportBaseUrl)
managingExposeeEndpoint = ManagingExposeeEndpoint(baseURL: descriptor.bucketBaseUrl)
And that looks as if the 2 assignments are swapped, shouldn't managingExposeeEndpoint
go to thedescriptor.reportBaseUrl
and vice versa?
In the Exposure Notification api usage:
https://github.com/DP-3T/dp3t-sdk-ios/blob/master/EXPOSURE_NOTIFICATION_API_USAGE.md
We found this:
We are only allowed to call detectExposures() 20 times within 24h. Because we check for every of the past 10 days individually, this allows us to check for exposure twice per day. These checks happen after 6am and 6pm (swiss time) when the BackgroundTask is scheduled the next time or the app is opened. All 10 days are checked individually and if one fails it is retried on the next run. No checks are made between midnight UTC and 6am (swiss time) to prevent exceeding the rate limit per 24h.
I can't find in the code where these checks (6am, 6pm) are scheduled. The piece of code I've found:
private func scheduleBackgroundTask() {
logger.trace()
let taskRequest = BGProcessingTaskRequest(identifier: DP3TBackgroundTaskManager.taskIdentifier)
taskRequest.requiresNetworkConnectivity = true
do {
handler?.didScheduleBackgrounTask()
try BGTaskScheduler.shared.submit(taskRequest)
} catch {
logger.error("background task schedule failed error: %{public}@", error.localizedDescription)
}
}
Register a BGProcessingTaskRequest wich documentation says:
Schedule a processing task request to ask that the system launch your app when conditions are favorable for battery life to handle deferrable, longer-running processing, such as syncing, database maintenance, or similar tasks. The system will attempt to fulfill this request to the best of its ability within the next two days as long as the user has used your app within the past week.
Is there any other place in the code where the schedurle restriccions of twice a day are set? Whe are having trouble validating the background checks of the app. It seems it doesn't run in all devices...
First time SWIFTer here, so caution.
In https://github.com/DP-3T/dp3t-sdk-ios/blob/develop/Sources/DP3TSDK/Cryptography/Crypto.swift#L11, the connection with the CommonCrypto
library looks somewhat convoluted. For once I prefer the stackoverflow answer here: https://stackoverflow.com/a/25391020/1573347
Dear all,
First of all - I'm not versed in Swift, so I may misunderstand code, but here it goes:
In the API consuming part in ExposeeServiceClient.swift you are raising an error if the batchReleaseTime
of the response does not match that of the request here. Isn't this redundant and shouldn't the backend have the last word so to say about the batch release time?
I may also be a bit confused about the meaning of the release time - per my understanding it is the last completed/concluded time block (defaulting to 2h) up until now. So if the server has 2h release time blocks, and I request a block of keys at say 15:15, shouldn't I get all keys that were released between 12:00 and 14:00?
ExposureNotificationMatcher imports ZIPFoundation
You need to add a dependency at DP3TSDK.podspec: spec.dependency 'ZIPFoundation', '~> 0.9'?
Hi!
With the SDK, would all the processes of BT reading and writing the SDK in the prestandard tag works with app in background? And on iOS <13?
Hello,
Thank you for your amazing work on this SDK! ๐
I'm working on a non-profit and open source initiative to provide an alternative contact tracing application for France, based on DP-3T.
We would like to adapt your demo app, but we don't have iOS/Android developers available at the moment. But we have React ones (I am), so we are looking for a React native binding.
Do you have plan for that?
I found this: https://github.com/wix-incubator/react-native-dp3t
But it is not very active.
It is probably not a DP-3T core team priority, but if there are other people asking the same question, maybe we could work together :)
Hi
I asked the authors of the Spanish radar covid app, to implement the feature of low risk encounters based on
https://github.com/corona-warn-app/cwa-documentation/blob/master/transmission_risk.pdf
They answered me that
Sorry, that's not possible for the moment because we are using the dp3t protocol and this functionality is not supported currently.
is this true? Can anybody please comment on this.
thanks and regards
description
is called transparently any time a string representation is needed. Making the default behavior of (debug) printing a key expose the secret increases changes of a developer unintentionally leaking to keys to logs or other places.
Please consider exposing the secret only via methods or properties which clearly indicate this.
With ENv1 it is not possible to export the current Key on the same day, this issue is solved by the DP3T SDK by scheduling an export of the missing key on the next day.
Starting with iOS 13.7 it is not possible anymore to call getDiagnosisKey if the EN Framework is disabled and the app is in the background.
Apple unfortunately decreased the rate-limit of calling EN.detectExposured in iOS 13.7 to 15 calls per 24h instead of the 20 calls (2x a full sync per day) we were allowed to make on previous iOS versions.
With this limitation, the app is only to check against 15 days/day instead of 20 days/day.
We are in contact with Apple about this.
The following test
<
instead of <=
.
Security implications thereof are pretty bad, see for example a similar bug from issue reference_implementation/#12. (Essentially, anyone can compute valid, infected EphIDs from some published SK and inject them to the victim the same day as bucketDate.)
In my IOS App I could never see any actual GET /v1/exposed
request. Possible explanation (unless I made something wrong, which of course is very well possible), see file Sources/DP3TSDK/Networking/KnownCasesSynchronizer.swift
:
private func internalSync(service: ExposeeServiceClient, callback: Callback?){
let now = Date().timeIntervalSince1970
var nextBatch: TimeInterval!
// Note that defaults.lastLoadedBatchReleaseTime initially is nil, so "else" part will be used:
if let lastBatch = defaults.lastLoadedBatchReleaseTime, ... {...} else {
nextBatch = now - now.truncatingRemainder(dividingBy: NetworkingConstants.batchLenght)
// This will be "now rounded down to last 2 hour interval (batchLenght)";
// if it now is 11am, nextBatch will be 10am
}
let batchesToLoad = Int((now - nextBatch) / NetworkingConstants.batchLenght)
// 'now - nextBatch' is 'now.truncatingRemainder(dividingBy: NetworkingConstants.batchLenght)',
// which is usually smaller that batchLenght (in the example: 1 hour)
// integer division by batchLenght will result in 0!
for batchIndex in (0 ..< batchesToLoad) {...}
// so this loop won't execute, 0 is never smaller than 0
Does synchronization with backend happens automatically as Android or we have to force it (Pressing the button)?
I let it more than half an hour and no synchronization happen.
Also the background has status denied.
After one successful force sync, when I try again this error pop ups
networkingError The operation couldn't be completed. (DP3TSDK_CALIBRATION.DP3TNetworkingError error 4).
Update 1
I had Background App Refresh to off
Update 2
Wi-Fi is off, pressing sync does not produce any error and updates time
it's not clear to me how to "add the app name has to be registered in the discovery service"
I could not find a website with documentation (readthedocs, etc.), clearly explaining what the app is doing and how it works.
Any plans to publish one in the next days?
internal func checkContacts(secretKey: Data, onsetDate: DayDate, bucketDate: Date, getContacts: (DayDate) -> ([Contact])) throws -> [Contact] {
var dayToTest: DayDate = onsetDate
if -dayToTest.dayMin.timeIntervalSinceNow > TimeInterval(CryptoConstants.numberOfDaysToKeepData) * TimeInterval.day {
dayToTest = DayDate(date: Date().addingTimeInterval(TimeInterval(CryptoConstants.numberOfDaysToKeepData) * TimeInterval.day * (-1)))
}
If onsetDate
is older than the 21 day window, dayToTest
now points to the oldest day in the queue (21 days ago), which is some days after onsetDate (with a day-offset > 0). secretKey
can't return any matches for this day because it was used for onsetDate
, notdayToTest
, but that's ok, as it is out of window anyway. What's missed here is to forward secretKeyForDay
forward for the same amount of days as dayToTest
(offset times secretKeyForDay = getSKt1(SKt0: secretKeyForDay)
), because otherwise:
...
while dayToTest.timestamp <= bucketDate.timeIntervalSince1970 {
let contactsOnDay = getContacts(dayToTest)
guard !contactsOnDay.isEmpty else {
dayToTest = dayToTest.getNext()
secretKeyForDay = getSKt1(SKt0: secretKeyForDay)
continue
}
...
dayToTest = dayToTest.getNext()
secretKeyForDay = getSKt1(SKt0: secretKeyForDay)
}
return matchingContacts
}
Whenever a day change occurs, dayToTest
and secretKeyForDay
will both be forwarded, the day offset remains the same. No contacts will ever be found withoud preforwarding secretKeyForDay
However, bucketDate.timeIntervalSince1970
might at some point reach into the stored queue (not older than 21 days), and there contacts could be present. So in this - admittedly not very probable case - actual expositions could be missed.
The white paper mention that Smartphones pick a random order in which to broadcast the EphIDs during the day. It is not clear to me whether this random ordering bring anything to security, but plausible that this random order should be unpredictable, i.e., relying on a cryptographically secure RNG. Swift APIs allow to pass a generator as a parameter, cf. shuffle(using:)
As a side note, secure shuffling is implemented for the Android flavour:
Hi,
I do some test with the sample app, everything was fine i use it with an iPad and an iPhone.
When i turn off the Bluetooth in one of the two device and turn on after 30 minutes, something goes wrong. One of the two devices seems like act only ad receivers the other one Only as sender
Hello,
Do you plan to support iOS versions prior to 13.5? So the implicit question is: is there any plan to implement DP-3T and therefore be fully compliant with the swiss Law on Epidemics Art. 60a?
According to the JWT documentation, if the constructor fails, it could also be that the signature was wrong.
Decode a JWT from a JWT string
A JWT struct can be initialized from a JWT string. If a JWTVerifier is provided it will be used to verify the signature before initialization
Whereas the validateClaims
function only validates the claims on the JWT (e.g. nbf or exp) and does nothing regarding the signature:
We should define a common ground, on how the User-Agent should look like. I think it event would make sense, to change the format to a map or something like that, to have a more robust way of parsing the arguments.
See the following issue to track the backend version:
DP-3T/dp3t-sdk-backend#273
Hi
When the bluetooth is turned off and the DP3TTracingDelegate is active. We never receive the state:
TracingState.inactive(error) whith error DP3TTracingError.bluetoothTurnedOff
We always receive TracinState.active even activating and disabling tracing with DP3TTracing.startTracing/stopTracing
Regards
As we can see in the documentation:
"The SDK does not automatically sync with the backend for new exposed users. The app is responsible for fetching the new exposed users as it sees fit (periodically or via user input):"
But it's needed to enable background processiong and setup the following id: "org.dpppt.exposure-notification" in the BGTaskSchedulerPermittedIdentifiers
What is it intended for?
I want to periodically perfrom the sync with the backend and need this point to be clarified
It is not clear weather when one should include DP3TSDK and when use ST3PSDK_CALIBRATION
Also the given initialization function
DP3TTracing.initialize
has a ) missing
Please give one or two exemples that compile
Thankyou
Hello,
I tried to make a simple "HelloWorld Contact Tracing" Swift file for iOs
https://github.com/pelinquin/kissact/blob/master/hello_DP3T.swift
But I had to add a button to get the last Handshake.
I seems that the SQL database is mandatory with the SDK.
I would have prefer to have to register a callback function, for each received message.
I may want to use my own persistant system
The current implementation of checkContacts
supposes that the clocks between the sender and receiver are perfectly synchronized. It should test the day before and the day after the proposed epoch, too.
See also DP-3T/documents#135
The following commit 54df80e has introduced an inconsistency between a comment and the described function.
The comment of the setExposed
function on line 285 has been modified to refer to the new numberOfKeysToSubmit
variable instead of the hardcoded value of 14
.
numberOfKeysToSubmit
has a value of 30 in DP3TParameters.swift file.
This means that the following comment
// Share keys of last numberOfKeysToSubmit days
is understood as
// Share keys of last 30 days
However the setExposed
function is still using the hardcoded value of 14
in line 286
There is a discrepancy between the comment and the function.
The README says:
To support background fetch on devices with older iOS versions make sure to foreward the performFetchWithCompletionHandler call to the SDK.
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
DP3TTracing.performFetch(with: completionHandler)
}
However, Xcode says that Type 'DP3TTracing' has no member 'performFetch'
Once a device has received the InfectionStatus .exposed we are trying to bring it back to .healthy status by calling the sdk function DP3TTracing.resetInfectionStatus()
Initially the device goes back to .healthy but after the app is closed and the sdk is initiallized again. func DP3TTracingStateChanged(_ state: TracingState)
get the InfectionStatus .exposed with the same date as before.
This is a sumamry of the related logs:
2021-05-13T08:27:41+0200 debug ExpositionUseCase : New Tracing State --->
2021-05-13T08:27:41+0200 debug ExpositionUseCase : Status: exposed(days: [DP3TSDK.ExposureDay(identifier: BCEF6CC3-025B-4657-AFCB-8AAC9A1F9E49, exposedDate: 2021-05-12 00:00:00 +0000, reportDate: 2021-05-13 02:19:44 +0000, isDeleted: false)])
2021-05-13T08:27:41+0200 debug ExpositionUseCase : lastSync: Optional(2021-05-13 06:27:41 +0000)
2021-05-13T08:27:41+0200 debug ExpositionUseCase : tracingState active
2021-05-13T08:27:41+0200 debug ExpositionUseCase : <---
...
2021-05-13T08:27:41+0200 debug ExpositionCheckUseCase : Exposition outdated --> resetInfectionStatus called
...
2021-05-13T08:27:41+0200 debug ExpositionUseCase : New Tracing State --->
2021-05-13T08:27:41+0200 debug ExpositionUseCase : Status: healthy
2021-05-13T08:27:41+0200 debug ExpositionUseCase : lastSync: Optional(2021-05-13 06:27:41 +0000)
2021-05-13T08:27:41+0200 debug ExpositionUseCase : tracingState active
2021-05-13T08:27:41+0200 debug ExpositionUseCase : <---
...
2021-05-13T09:25:17+0200 debug SetupUseCase : [DP3TSDK] retreiving status from SDK
2021-05-13T09:25:17+0200 debug SetupUseCase : [exposureNotificationTracer] calling ENMananger.setExposureNotificationEnabled true
2021-05-13T09:25:19+0200 debug SetupUseCase : didScheduleBackgrounTask
2021-05-13T09:25:21+0200 debug SetupUseCase : [exposureNotificationTracer] calling ENMananger.activate
...
2021-05-13T09:25:21+0200 debug ExpositionUseCase : New Tracing State --->
2021-05-13T09:25:21+0200 debug ExpositionUseCase : Status: exposed(days: [DP3TSDK.ExposureDay(identifier: BCEF6CC3-025B-4657-AFCB-8AAC9A1F9E49, exposedDate: 2021-05-12 00:00:00 +0000, reportDate: 2021-05-13 02:19:44 +0000, isDeleted: false)])
2021-05-13T09:25:21+0200 debug ExpositionUseCase : lastSync: Optional(2021-05-13 06:27:41 +0000)
2021-05-13T09:25:21+0200 debug ExpositionUseCase : tracingState active
2021-05-13T09:25:21+0200 debug ExpositionUseCase : <---
Regards
Hello,
How can I access all Handshakes recorded with associated Date, ephID etc..
Any help ?
In order to support some other technologies, like react-native, please publish your code to CocoaPods.
Thanks in advance!
The file DP3TCryptoModule.swift
should also be commented with explanation of the input arguments to the methods.
Hello,
Is it possible to have a documentation or a more complete README regarding the current version of dp3t ?
Thank's you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.