If I create a form with a date input, I can only send current time and date. But if I change the system time than this will take wrong input. Is there any way to get actual current time and date??
While my earlier approach does work, I think there’s an easier solution. This is based on the Posix clock API. The reason why I didn’t consider this earlier is that this API is a relatively recent addition, being added to the system in the 2016 OS release (macOS 10.12, iOS 10, and friends). See the clock_gettime
man page for more background on this API.
The key thing to note here is that CLOCK_MONOTONIC
‘counts’ across sleep, unlikely the original Mach absolute time API. This allows your app to initially establish a trusted base time while the app is online and then determine a current trusted time relative to that.
The nice thing here is that there’s no messing around with other clocks, like gettimeofday
, or with kern.boottime
, which has always been a bit of a worry [1].
The main drawback continues to be that, if the user restarts their device, you can’t re-establish a trusted time until it comes online.
Oh, and it also raises the question about how to detect whether the device has been restarted. My recommendation is that you use a Posix semaphore for that. For example:
func restartState() -> RestartState {
let sem = sem_open(NAME, O_CREAT | O_EXCL)
if sem == SEM_FAILED {
let err = errno
switch err {
case EEXIST: return .hasNotRestarted
default: return .unknown(error: err)
}
} else {
let ok = sem_close(sem) >= 0
assert(ok)
return .hasRestarted
}
}
enum RestartState {
case hasRestarted
case hasNotRestarted
case unknown(error: CInt)
}
The basic idea is:
-
Create a semaphore with the exclusive flag (
O_EXCL
). -
If that works, the semaphore previously didn’t exist so this is the first time you’ve run this code since the device was restarted.
-
If it fails, you’ve run this code previously.
This relies on Posix semaphores being cleaned up on restart, which is a reasonable assumption IMO.
For more background on Posix semaphore, see sem_open
man page.
The only tricky part here is the value to use for NAME
. Posix semaphores are an IPC mechanism and the iOS sandbox puts strict limits on IPC. To avoid conflicts, set NAME
to GGG/NNN
, where GGG
is an app group ID and NNN
is a name of your choosing.
IMPORTANT Posix semaphore names are limited to 31 UTF-8 characters (PSEMNAMLEN
) so use a short app group ID and name.
Note This convention was documented in the App Sandbox Design Guide, which is no longer available from Apple )-: [2] I’ve filed a bug (r. 110052019) to get it added to the App Groups Entitlement docs, which discusses Posix semaphores in the abstract but misses out this key detail.
Finally, I want to reiterate some points from my earlier post:
-
The best way to get a secure timestamp is to use the network to get it from some trusted source.
-
The technique described above is only relevant if you need to do this while the network is unavailable.
-
If you end up using this technique, please file an enhancement request explaining why you need a secure timestamp. And I’d appreciate you posting your bug number here, just for the record.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] My main concern here is kern.boottime
, because it’s a source of entropy. See the footnote in this post.
[2] You can see an old copy of the Wayback Machine.
<https://web.archive.org/web/20221223145702mp_/https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24>