NielJoubert
9/16/2015 - 10:11 PM

DateTimeFraudCheck

@implementation NSDate (ServerTime)
+(void)setServerTime:(NSNumber *)timestamp {
    if (timestamp == nil) {
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:kServerTime];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:kServerTimeUptime];

    } else {
        [[NSUserDefaults standardUserDefaults] setObject:timestamp forKey:kServerTime];
        [[NSUserDefaults standardUserDefaults] setObject:@([self uptimeSeconds]) forKey:kServerTimeUptime];
    }
    [[NSUserDefaults standardUserDefaults] synchronize];
}
+(NSDate *)serverTime {
    NSNumber *lastServerTimestamp = [[NSUserDefaults standardUserDefaults] objectForKey:kServerTime];
    NSNumber *lastUptime = [[NSUserDefaults standardUserDefaults] objectForKey:kServerTimeUptime];
    
    if (lastServerTimestamp == nil || lastUptime == nil) {
        //the user has yet to sync up with the server we have no choice but to use the system time
        return [NSDate date];
    }
    
    int currentUptime = (int)[self uptimeSeconds];
    if (currentUptime < [lastUptime intValue]) {
        //there has been a reboot, we can't rely on the existing data, use the system time
        return [NSDate date];
    }
    
    //get the difference from the store uptime to the current uptime and offset the stored server time
    int delta = (currentUptime - [lastUptime intValue]);
    NSTimeInterval serverTime = [lastServerTimestamp intValue] + delta;
    
    return [NSDate dateWithTimeIntervalSince1970:serverTime];
}

+(time_t)uptimeSeconds {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    time_t now;
    time_t uptime = -1;
    
    (void)time(&now);
    
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
        uptime = now - boottime.tv_sec;
    }
    return uptime;
}
@end