I want my app to have a subscription service and the way I see it is by keeping timeIntervalSince1970 as an "until" date. But that is easily avoidable if the user changes system's current time. Is there any better way to track that in offline mode?
take a look at this post1, it explain how to measure passed time, independent of clock and time zone changes.
you also take a look at this post2, it explain how detect device time change only when it is changed manually
Let me know if this helps you :)
Related
I need to set up user proof time keeping in my current project. I have found a lot of different question around this, but none that seem to have the answer I am looking for. These are the questions i have looked at so far:
XCODE: How to get/verify ACCURATE timestamp from device
Is it possible to get the atomic clock timestamp from the iphone GPS?
How can I get the real time in iPhone, not the time set by user in Settings?
I have several options for getting a time from a server connection but I need to have an offline solution too.
1.
It seems that using CLLocation gets the same time as as the device clock. Is there away to get the actual GPS time?
2.
I know the system time settings are not a public API thus can't be changed. Is it possible to find out if the device has the auto time setting turned on? If the auto time is on then I can rely on the system time for my purposes and if it's off then record that so I know that the time recorded is not to be trusted?
Just wanted to post my solution, incase some one else has the same issue.
After much research i found that getting GPS time of time setting info was not possible.
This solution isn't perfect nor real time but works for my purpose.
I have implemented a time check using cloud time each time the app comes on line. When the device re-establishes a server connection to sync events created off line i have put a verification that takes the last object device time and the new object device time and calculates the elapsed time between the two. (using NSdates so that daylight savings is covered) then do the same with the last available server time and the most recent server time. I then compare the results and if they are not within my margin of error the events are marked as invalid.
Hope that makes sense and is helpful for others.
Currently I'm writing an app that will need every iOS devices to have some sort of synchronized time in order to function correctly. I know I can use NSDate to get current time, but I'm not sure if all iOS devices (no matter what location setting it has, or maybe user sets the time manually) will have same NSDate. The synced time has to be accurate enough (< 10ms difference maximum). Can I just use NSDate directly?
No, you cannot rely on NSDate to give you this information.
You can use a Real Time server to provide this information.
Check, it may help you.
Check also about NTP protocol, you can easily use this github project to get from a trusted time server, the current time, whiteout rely on the device.
but I'm not sure if all iOS devices (no matter what location setting it has, or maybe user sets the time manually) will have same NSDate.
Obviously they won't, because some people will set the time manually, so it could be quite far off.
Settings -> General -> Date & Time -> Switch off "Automatically" -> set the time to whatever you wish. So clearly what you ask for cannot be possible.
If you want synchronisation, then the only way you can do this between multiple device is with a central server that keeps the time, and everyone uses the time reported by that server, in your code.
It´s possible, detect with Swift or Objective-C if in the settings Date & Time, "Set Automatically" is enabled ???
In android there is "Settings.Global.AUTO_TIME_ZONE", I am looking a equivalent in Swift/Objective-C
No, there is no way to do this given the standard SDK. There are jailbroken/private API methods, but I would not recommend relying on them.
If your goal is to keep someone from going back in the past (to circumvent some kind of timed trial) you could store the most recent date you've seen (maybe at startup) in the NSUserDefaults, and if at any time you notice that the current time is more than one hour earlier than the most recently stored time, you can probably safely assume the user has manually changed their time.
But without knowing why you want to do this, it's difficult to offer better suggestions.
I want to deploy managed iOS devices to employees of the company, and the app they will use will timestamp data that will be recorded locally, then forwarded. I need those timestamps to be correct, so I must prevent the user from adjusting the time on the device, recording a value, then resetting the date and time. Date and time will be configured to come from the network automatically, but the device may not have network connectivity at all times (otherwise I would just read network time every time a data value is recorded). I haven't seen an option in Apple Configurator to prevent changing the date and time, so is there some other way to do this?
You won't be able to prevent a user either changing their clock or just hitting your API directly as other commentators have posted. These are two separate issues and can be solved by having a local time that you control on the device and by generating a hashed key of what you send to the server.
Local Time on Device:
To start, make an API call when you start the app which sends back a timestamp from the server; this is your 'actual time'. Now store this on the device and run a timer which uses a phone uptime function (not mach_absolute_time() or CACurrentMediaTime() - these get weird when your phone is in standby mode) and a bit of math to increase that actual time every second. I've written an article on how I did this for one of my apps at (be sure to read the follow up as the original article used CACurrentMediaTime() but that has some bugs). You can periodically make that initial API call (i.e. if the phone goes into the background and comes back again) to make sure that everything is staying accurate but the time should always be correct so long as you don't restart the phone (which should prompt an API call when you next open the app to update the time).
Securing the API:
You now have a guaranteed* accurate time on your device but you still have an issue in that somebody could send the wrong time to your API directly (i.e. not from your device). To counteract this, I would use some form of salt/hash with the data you are sending similar to OAuth. For example, take all of the parameters you are sending, join them together and hash them with a salt only you know and send that generated key as an extra parameter. On your server, you know the hash you are using and the salt so you can rebuild that key and check it with the one that was sent; if they don't match, somebody is trying to play with your timestamp.
*Caveat: A skilled attacked could hi-jack the connection so that any calls to example.com/api/timestamp come from a different machine they have set up which returns the time they want so that the phone is given the wrong time as the starting base. There are ways to prevent this (obfuscation, pairing it with other data, encryption) but that becomes a very open-ended question very quickly so best asked elsewhere. A combination of the above plus a monitor to notice weird times might be the best thing.
There doesn't appear to be any way to accomplish what you're asking for. There doesn't seem to be a way to stop the user from being able to change the time. But beyond that, even if you could prevent them from changing the time, they could let their device battery die, then plug it in and turn it on where they don't have a net connection, and their clock will be wrong until it has a chance to set itself over a network. So even preventing them from changing the time won't guarantee accuracy.
What you could do is require a network connection to record values, so that you can verify the time on a server. If you must allow it to work without a net connection, you could at least always log the current time when the app is brought up and note if the time ever seems to go backwards. You'll know something is up if the timestamp suddenly is earlier than the previous timestamp. You could also do this check perhaps only when they try to record a value. If they record a value that has a timestamp earlier than any previous recorded value, you could reject it, or log the event so that the person can be questioned about it at a later time.
This is also one of those cases where maybe you just have to trust the user not to do this, because there doesn't seem to be a perfect solution to this.
The first thing to note is that the user will always be able to forge messages to your server in order to create incorrect records.
But there are some useful things you can use to at least notice problems. Most of the time the best way to secure this kind of system is to focus on detection, and then publicly discipline anyone who has gone out of their way to circumvent policy. Strong locks are meaningless unless there's a cop who's eventually going to show up and stop you.
Of course you should first assume that any time mistakes are accidental. But just publicly "noticing" that someone's device seems to be "misbehaving" is often enough to make bad behaviors go away.
So what can you do? The first thing is to note the timestamps of things when they show up at the server. Timestamps should always move forward in time. So if you've already seen records from a device for Monday, you should not later receive records for the previous Sunday. The same should be true for your app. You can keep track of when you are terminated in NSUserDefaults (as well as posting this information to the server). You should not generally wake up in the past. If you do, complain to your server.
Watch for UIApplicationSignificantTimeChangeNotification. I believe you'll receive it if the time is manually changed (you'll receive it in several other cases as well, most of them benign). Watch for time moving significantly backwards. Complain to your server.
Pay attention to mach_absolute_time(). This is the time since the device was booted and is not otherwise modifiable by the user without jailbreaking. It's useful for distinguishing between reboots and other events. It's in a weird time unit, but it can be converted to human time as described in QA1398. If the mach time difference is more than an hour greater than the wall clock time, something is weird (DST changes can cause 1 hour). Complain to your sever.
All of these things could be benign. A human will need to investigate and make a decision.
None of these things will ensure that your records are correct if there is a dedicated and skilled attacker involved. As I said, a dedicated and skilled attacker could just send you fake messages. But these things, coupled with monitoring and disciplinary action, make it dangerous for insiders to even experiment with how to beat the system.
You cannot prevent the user from changing time.
Even the time of an Location is adjusted by Apple, and not a real GPS time.
You could look at mach kernel time, which is a relative time.
Compare that to the time when having last network connection.
But this all sounds not reliable.
I'm trying to use relevantDate to refine when the passes for my app are shown.
The relevantDate options I know about are: specify a start and end time on a single day, or specify a single time which seems to show the pass in the lock screen for about a four-hour window in either direction (!), at least for the "generic" pass type.
It seems like there ought to be a way to specify, e.g., for a coupon, that it should be shown on the lock screen when they're in the store for the next two weeks, at which point it should expire. Is there? If so, what is it?
Sorry, there's not currently a way to do this.
Relevance is a cooperative effort between you and the system. Your pass gives a point in time (the relevant date) and/or a point in space (the relevant locations). There's no API to provide a duration or a region. The system decides what radius to use around that location and what window of time to use around the date. There is some documentation for the relevant locations in the Passbook guide but the time window is not documented. In practice, the time window is on the order of 4-8 hours, depending on the pass style.
You should go on Apple's bug report page and file an enhancement request, describing how it would add value to your coupons to be relevant for multiple days.
Although not quite what you are looking for, you could send a push update to remove the locations after the promotion period ends.
If you have a promotion that is valid in a particular store, then you could use locations with relevantText appropriate for the promotion period E.g. 20% Off, Ends Jan 20. Once the promotion ends, you then send a push with no locations (or replace with a new offer).
The relevantDate key is not supported by the coupon or storeCard pass types and there is no way to specify a custom lock screen message for a time based alert, so personally I prefer to use location alerts whenever a location is known. The exception would be when it makes sense to remind the user a few hours beforehand (E.g. for a dental appointment or scheduled personal training session).