FRANotification.m revision a1e92b2783be4bfeb0c7e267223cc7779a6f324c
0N/A/*
0N/A * The contents of this file are subject to the terms of the Common Development and
0N/A * Distribution License (the License). You may not use this file except in compliance with the
0N/A * License.
0N/A *
0N/A * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
0N/A * specific language governing permission and limitations under the License.
0N/A *
0N/A * When distributing Covered Software, include this CDDL Header Notice in each file and include
0N/A * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
0N/A * Header, with the fields enclosed by brackets [] replaced by your own identifying
0N/A * information: "Portions copyright [year] [name of copyright owner]".
0N/A *
0N/A * Copyright 2016 ForgeRock AS.
0N/A */
0N/A
0N/A
0N/A
0N/A#import "FRAIdentityDatabase.h"
0N/A#import "FRAMessageUtils.h"
0N/A#import "FRAModelObjectProtected.h"
0N/A#import "FRANotification.h"
0N/A#import "FRAPushMechanism.h"
0N/A
0N/A/*!
0N/A * All notifications are expected to be able to transition from the initial state
0N/A * of pending, to the final state of approved or denied.
0N/A */
0N/A@implementation FRANotification {
0N/A NSDateFormatter *formatter;
0N/A}
0N/A
0N/A@synthesize pending;
0N/A
0N/Astatic double const ONE_MINUTE_IN_SECONDS = 60.0;
0N/Astatic double const ONE_HOUR_IN_SECONDS = 3600.0;
0N/Astatic double const ONE_DAY_IN_SECONDS = 86400.0;
0N/Astatic double const TWO_DAYS_IN_SECONDS = 172800.0;
0N/Astatic double const ONE_WEEK_IN_SECONDS = 604800.0;
0N/Astatic NSString * const STRING_DATE_FORMAT = @"dd/MM/yyyy";
0N/A
0N/A- (instancetype)initWithDatabase:(FRAIdentityDatabase *)database messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive {
0N/A self = [super initWithDatabase:database];
0N/A if (self) {
0N/A pending = YES;
0N/A _approved = NO;
0N/A _denied = NO;
0N/A
0N/A formatter = [[NSDateFormatter alloc] init];
0N/A [formatter setDateFormat:STRING_DATE_FORMAT];
0N/A _messageId = messageId;
0N/A _challenge = challenge;
0N/A _timeReceived = timeReceived;
0N/A _timeToLive = timeToLive;
0N/A _timeExpired = [timeReceived dateByAddingTimeInterval:timeToLive];
0N/A }
0N/A return self;
0N/A}
0N/A
0N/A+ (instancetype)notificationWithDatabase:(FRAIdentityDatabase *)database messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive {
0N/A return [[FRANotification alloc] initWithDatabase:database messageId:messageId challenge:challenge timeReceived:timeReceived timeToLive:timeToLive];
0N/A}
0N/A
0N/A- (NSString *)age {
0N/A NSTimeInterval age = [[NSDate date] timeIntervalSinceDate:self.timeReceived];
0N/A if (age < ONE_MINUTE_IN_SECONDS) {
0N/A return @"less than a minute ago";
0N/A } else if (age < ONE_HOUR_IN_SECONDS) {
0N/A // TODO: Handle "1 minutes ago" as a special case
0N/A return [NSString stringWithFormat:@"%ld minutes ago", (long)((age/ONE_MINUTE_IN_SECONDS)+0.5)];
0N/A } else if (age < ONE_DAY_IN_SECONDS) {
0N/A // TODO: Handle "1 hours ago" as a special case
0N/A return [NSString stringWithFormat:@"%ld hours ago", (long)(age / ONE_HOUR_IN_SECONDS)];
0N/A } else if (age < TWO_DAYS_IN_SECONDS) {
0N/A // TODO: Make this check more accurate, if it's 9am Tuesday then 2 days ago in seconds was 9am Sunday
0N/A // so time after 9am Sunday would be reported as "Yesterday" which is incorrect :-(
0N/A return @"Yesterday";
0N/A } else if (age < ONE_WEEK_IN_SECONDS) {
0N/A // TODO: Handle "1 days ago" as a special case
0N/A return [NSString stringWithFormat:@"%ld days ago", (long)(age / ONE_DAY_IN_SECONDS)];
0N/A } else {
0N/A return [formatter stringFromDate:self.timeReceived];
0N/A }
0N/A}
0N/A
0N/A- (BOOL)approveWithError:(NSError *__autoreleasing*)error {
0N/A _approved = YES;
0N/A pending = NO;
0N/A if ([self isStored]) {
0N/A if (![self.database updateNotification:self error:error]) {
0N/A return NO;
0N/A }
0N/A FRAPushMechanism *mechanism = (FRAPushMechanism *)_parent;
0N/A if (mechanism) {
0N/A NSDictionary *data = @{@"response":[FRAMessageUtils generateChallengeResponse:_challenge secret:mechanism.secret]};
0N/A [FRAMessageUtils respondWithEndpoint:mechanism.authEndpoint
0N/A base64Secret:mechanism.secret
0N/A messageId:_messageId
0N/A data:data
0N/A handler:^(NSInteger statusCode, NSError *error) {
0N/A if (statusCode != 200) {
0N/A // TODO: Handle error
0N/A }
0N/A }];
0N/A }
0N/A }
0N/A return YES;
0N/A}
0N/A
0N/A- (BOOL)denyWithError:(NSError *__autoreleasing*)error {
0N/A _approved = NO;
0N/A pending = NO;
0N/A _denied = YES;
0N/A if ([self isStored]) {
0N/A if (![self.database updateNotification:self error:error]) {
0N/A return NO;
0N/A }
0N/A }
0N/A return YES;
0N/A}
0N/A
0N/A- (BOOL)isPending {
0N/A return pending && ![self isExpired];
0N/A}
0N/A
0N/A- (BOOL)isExpired {
0N/A return pending && [[NSDate date] timeIntervalSinceDate:_timeExpired] > 0;
0N/A}
0N/A
0N/A@end
0N/A