| 1 | 
           efrain | 
           1 | 
           /*
  | 
        
        
            | 
            | 
           2 | 
            * Copyright 2019 Google
  | 
        
        
            | 
            | 
           3 | 
            *
  | 
        
        
            | 
            | 
           4 | 
            * Licensed under the Apache License, Version 2.0 (the "License");
  | 
        
        
            | 
            | 
           5 | 
            * you may not use this file except in compliance with the License.
  | 
        
        
            | 
            | 
           6 | 
            * You may obtain a copy of the License at
  | 
        
        
            | 
            | 
           7 | 
            *
  | 
        
        
            | 
            | 
           8 | 
            *      http://www.apache.org/licenses/LICENSE-2.0
  | 
        
        
            | 
            | 
           9 | 
            *
  | 
        
        
            | 
            | 
           10 | 
            * Unless required by applicable law or agreed to in writing, software
  | 
        
        
            | 
            | 
           11 | 
            * distributed under the License is distributed on an "AS IS" BASIS,
  | 
        
        
            | 
            | 
           12 | 
            * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  | 
        
        
            | 
            | 
           13 | 
            * See the License for the specific language governing permissions and
  | 
        
        
            | 
            | 
           14 | 
            * limitations under the License.
  | 
        
        
            | 
            | 
           15 | 
            */
  | 
        
        
            | 
            | 
           16 | 
              | 
        
        
            | 
            | 
           17 | 
           #import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h"
  | 
        
        
            | 
            | 
           18 | 
              | 
        
        
            | 
            | 
           19 | 
           #import "FirebaseMessaging/Sources/FIRMessagingConstants.h"
  | 
        
        
            | 
            | 
           20 | 
           #import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
  | 
        
        
            | 
            | 
           21 | 
           #import "FirebaseMessaging/Sources/FIRMessagingUtilities.h"
  | 
        
        
            | 
            | 
           22 | 
              | 
        
        
            | 
            | 
           23 | 
           /**
  | 
        
        
            | 
            | 
           24 | 
            *  @enum Token Info Dictionary Key Constants
  | 
        
        
            | 
            | 
           25 | 
            *  @discussion The keys that are checked when a token info is
  | 
        
        
            | 
            | 
           26 | 
            *              created from a dictionary. The same keys are used
  | 
        
        
            | 
            | 
           27 | 
            *              when decoding/encoding an archive.
  | 
        
        
            | 
            | 
           28 | 
            */
  | 
        
        
            | 
            | 
           29 | 
           /// Specifies a dictonary key whose value represents the authorized entity, or
  | 
        
        
            | 
            | 
           30 | 
           /// Sender ID for the token.
  | 
        
        
            | 
            | 
           31 | 
           static NSString *const kFIRInstanceIDAuthorizedEntityKey = @"authorized_entity";
  | 
        
        
            | 
            | 
           32 | 
           /// Specifies a dictionary key whose value represents the scope of the token,
  | 
        
        
            | 
            | 
           33 | 
           /// typically "*".
  | 
        
        
            | 
            | 
           34 | 
           static NSString *const kFIRInstanceIDScopeKey = @"scope";
  | 
        
        
            | 
            | 
           35 | 
           /// Specifies a dictionary key which represents the token value itself.
  | 
        
        
            | 
            | 
           36 | 
           static NSString *const kFIRInstanceIDTokenKey = @"token";
  | 
        
        
            | 
            | 
           37 | 
           /// Specifies a dictionary key which represents the app version associated
  | 
        
        
            | 
            | 
           38 | 
           /// with the token.
  | 
        
        
            | 
            | 
           39 | 
           static NSString *const kFIRInstanceIDAppVersionKey = @"app_version";
  | 
        
        
            | 
            | 
           40 | 
           /// Specifies a dictionary key which represents the GMP App ID associated with
  | 
        
        
            | 
            | 
           41 | 
           /// the token.
  | 
        
        
            | 
            | 
           42 | 
           static NSString *const kFIRInstanceIDFirebaseAppIDKey = @"firebase_app_id";
  | 
        
        
            | 
            | 
           43 | 
           /// Specifies a dictionary key representing an archive for a
  | 
        
        
            | 
            | 
           44 | 
           /// `FIRInstanceIDAPNSInfo` object.
  | 
        
        
            | 
            | 
           45 | 
           static NSString *const kFIRInstanceIDAPNSInfoKey = @"apns_info";
  | 
        
        
            | 
            | 
           46 | 
           /// Specifies a dictionary key representing the "last cached" time for the token.
  | 
        
        
            | 
            | 
           47 | 
           static NSString *const kFIRInstanceIDCacheTimeKey = @"cache_time";
  | 
        
        
            | 
            | 
           48 | 
           /// Default interval that token stays fresh.
  | 
        
        
            | 
            | 
           49 | 
           static const NSTimeInterval kDefaultFetchTokenInterval = 7 * 24 * 60 * 60;  // 7 days.
  | 
        
        
            | 
            | 
           50 | 
              | 
        
        
            | 
            | 
           51 | 
           @implementation FIRMessagingTokenInfo
  | 
        
        
            | 
            | 
           52 | 
              | 
        
        
            | 
            | 
           53 | 
           - (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity
  | 
        
        
            | 
            | 
           54 | 
                                              scope:(NSString *)scope
  | 
        
        
            | 
            | 
           55 | 
                                              token:(NSString *)token
  | 
        
        
            | 
            | 
           56 | 
                                         appVersion:(NSString *)appVersion
  | 
        
        
            | 
            | 
           57 | 
                                      firebaseAppID:(NSString *)firebaseAppID {
  | 
        
        
            | 
            | 
           58 | 
             self = [super init];
  | 
        
        
            | 
            | 
           59 | 
             if (self) {
  | 
        
        
            | 
            | 
           60 | 
               _authorizedEntity = [authorizedEntity copy];
  | 
        
        
            | 
            | 
           61 | 
               _scope = [scope copy];
  | 
        
        
            | 
            | 
           62 | 
               _token = [token copy];
  | 
        
        
            | 
            | 
           63 | 
               _appVersion = [appVersion copy];
  | 
        
        
            | 
            | 
           64 | 
               _firebaseAppID = [firebaseAppID copy];
  | 
        
        
            | 
            | 
           65 | 
             }
  | 
        
        
            | 
            | 
           66 | 
             return self;
  | 
        
        
            | 
            | 
           67 | 
           }
  | 
        
        
            | 
            | 
           68 | 
              | 
        
        
            | 
            | 
           69 | 
           - (BOOL)isFreshWithIID:(NSString *)IID {
  | 
        
        
            | 
            | 
           70 | 
             // Last fetch token cache time could be null if token is from legacy storage format. Then token is
  | 
        
        
            | 
            | 
           71 | 
             // considered not fresh and should be refreshed and overwrite with the latest storage format.
  | 
        
        
            | 
            | 
           72 | 
             if (!IID) {
  | 
        
        
            | 
            | 
           73 | 
               return NO;
  | 
        
        
            | 
            | 
           74 | 
             }
  | 
        
        
            | 
            | 
           75 | 
             if (!_cacheTime) {
  | 
        
        
            | 
            | 
           76 | 
               return NO;
  | 
        
        
            | 
            | 
           77 | 
             }
  | 
        
        
            | 
            | 
           78 | 
              | 
        
        
            | 
            | 
           79 | 
             // Check if it's consistent with IID
  | 
        
        
            | 
            | 
           80 | 
             if (![self.token hasPrefix:IID]) {
  | 
        
        
            | 
            | 
           81 | 
               return NO;
  | 
        
        
            | 
            | 
           82 | 
             }
  | 
        
        
            | 
            | 
           83 | 
              | 
        
        
            | 
            | 
           84 | 
             // Check if app has just been updated to a new version.
  | 
        
        
            | 
            | 
           85 | 
             NSString *currentAppVersion = FIRMessagingCurrentAppVersion();
  | 
        
        
            | 
            | 
           86 | 
             if (!_appVersion || ![_appVersion isEqualToString:currentAppVersion]) {
  | 
        
        
            | 
            | 
           87 | 
               FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManager004,
  | 
        
        
            | 
            | 
           88 | 
                                       @"Invalidating cached token for %@ (%@) due to app version change.",
  | 
        
        
            | 
            | 
           89 | 
                                       _authorizedEntity, _scope);
  | 
        
        
            | 
            | 
           90 | 
               return NO;
  | 
        
        
            | 
            | 
           91 | 
             }
  | 
        
        
            | 
            | 
           92 | 
              | 
        
        
            | 
            | 
           93 | 
             // Check if GMP App ID has changed
  | 
        
        
            | 
            | 
           94 | 
             NSString *currentFirebaseAppID = FIRMessagingFirebaseAppID();
  | 
        
        
            | 
            | 
           95 | 
             if (!_firebaseAppID || ![_firebaseAppID isEqualToString:currentFirebaseAppID]) {
  | 
        
        
            | 
            | 
           96 | 
               FIRMessagingLoggerDebug(
  | 
        
        
            | 
            | 
           97 | 
                   kFIRMessagingMessageCodeTokenInfoFirebaseAppIDChanged,
  | 
        
        
            | 
            | 
           98 | 
                   @"Invalidating cached token due to Firebase App IID change from %@ to %@", _firebaseAppID,
  | 
        
        
            | 
            | 
           99 | 
                   currentFirebaseAppID);
  | 
        
        
            | 
            | 
           100 | 
               return NO;
  | 
        
        
            | 
            | 
           101 | 
             }
  | 
        
        
            | 
            | 
           102 | 
              | 
        
        
            | 
            | 
           103 | 
             // Check whether locale has changed, if yes, token needs to be updated with server for locale
  | 
        
        
            | 
            | 
           104 | 
             // information.
  | 
        
        
            | 
            | 
           105 | 
             if (FIRMessagingHasLocaleChanged()) {
  | 
        
        
            | 
            | 
           106 | 
               FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenInfoLocaleChanged,
  | 
        
        
            | 
            | 
           107 | 
                                       @"Invalidating cached token due to locale change");
  | 
        
        
            | 
            | 
           108 | 
               return NO;
  | 
        
        
            | 
            | 
           109 | 
             }
  | 
        
        
            | 
            | 
           110 | 
              | 
        
        
            | 
            | 
           111 | 
             // Locale is not changed, check whether token has been fetched within 7 days.
  | 
        
        
            | 
            | 
           112 | 
             NSTimeInterval lastFetchTokenTimestamp = [_cacheTime timeIntervalSince1970];
  | 
        
        
            | 
            | 
           113 | 
             NSTimeInterval currentTimestamp = FIRMessagingCurrentTimestampInSeconds();
  | 
        
        
            | 
            | 
           114 | 
             NSTimeInterval timeSinceLastFetchToken = currentTimestamp - lastFetchTokenTimestamp;
  | 
        
        
            | 
            | 
           115 | 
             return (timeSinceLastFetchToken < kDefaultFetchTokenInterval);
  | 
        
        
            | 
            | 
           116 | 
           }
  | 
        
        
            | 
            | 
           117 | 
              | 
        
        
            | 
            | 
           118 | 
           - (BOOL)isDefaultToken {
  | 
        
        
            | 
            | 
           119 | 
             return [self.scope isEqualToString:kFIRMessagingDefaultTokenScope];
  | 
        
        
            | 
            | 
           120 | 
           }
  | 
        
        
            | 
            | 
           121 | 
              | 
        
        
            | 
            | 
           122 | 
           #pragma mark - NSCoding
  | 
        
        
            | 
            | 
           123 | 
              | 
        
        
            | 
            | 
           124 | 
           - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
  | 
        
        
            | 
            | 
           125 | 
             // These value cannot be nil
  | 
        
        
            | 
            | 
           126 | 
              | 
        
        
            | 
            | 
           127 | 
             id authorizedEntity = [aDecoder decodeObjectForKey:kFIRInstanceIDAuthorizedEntityKey];
  | 
        
        
            | 
            | 
           128 | 
             if (![authorizedEntity isKindOfClass:[NSString class]]) {
  | 
        
        
            | 
            | 
           129 | 
               return nil;
  | 
        
        
            | 
            | 
           130 | 
             }
  | 
        
        
            | 
            | 
           131 | 
              | 
        
        
            | 
            | 
           132 | 
             id scope = [aDecoder decodeObjectForKey:kFIRInstanceIDScopeKey];
  | 
        
        
            | 
            | 
           133 | 
             if (![scope isKindOfClass:[NSString class]]) {
  | 
        
        
            | 
            | 
           134 | 
               return nil;
  | 
        
        
            | 
            | 
           135 | 
             }
  | 
        
        
            | 
            | 
           136 | 
              | 
        
        
            | 
            | 
           137 | 
             id token = [aDecoder decodeObjectForKey:kFIRInstanceIDTokenKey];
  | 
        
        
            | 
            | 
           138 | 
             if (![token isKindOfClass:[NSString class]]) {
  | 
        
        
            | 
            | 
           139 | 
               return nil;
  | 
        
        
            | 
            | 
           140 | 
             }
  | 
        
        
            | 
            | 
           141 | 
              | 
        
        
            | 
            | 
           142 | 
             // These values are nullable, so only fail the decode if the type does not match
  | 
        
        
            | 
            | 
           143 | 
              | 
        
        
            | 
            | 
           144 | 
             id appVersion = [aDecoder decodeObjectForKey:kFIRInstanceIDAppVersionKey];
  | 
        
        
            | 
            | 
           145 | 
             if (appVersion && ![appVersion isKindOfClass:[NSString class]]) {
  | 
        
        
            | 
            | 
           146 | 
               return nil;
  | 
        
        
            | 
            | 
           147 | 
             }
  | 
        
        
            | 
            | 
           148 | 
              | 
        
        
            | 
            | 
           149 | 
             id firebaseAppID = [aDecoder decodeObjectForKey:kFIRInstanceIDFirebaseAppIDKey];
  | 
        
        
            | 
            | 
           150 | 
             if (firebaseAppID && ![firebaseAppID isKindOfClass:[NSString class]]) {
  | 
        
        
            | 
            | 
           151 | 
               return nil;
  | 
        
        
            | 
            | 
           152 | 
             }
  | 
        
        
            | 
            | 
           153 | 
              | 
        
        
            | 
            | 
           154 | 
             id rawAPNSInfo = [aDecoder decodeObjectForKey:kFIRInstanceIDAPNSInfoKey];
  | 
        
        
            | 
            | 
           155 | 
             if (rawAPNSInfo && ![rawAPNSInfo isKindOfClass:[NSData class]]) {
  | 
        
        
            | 
            | 
           156 | 
               return nil;
  | 
        
        
            | 
            | 
           157 | 
             }
  | 
        
        
            | 
            | 
           158 | 
              | 
        
        
            | 
            | 
           159 | 
             FIRMessagingAPNSInfo *APNSInfo = nil;
  | 
        
        
            | 
            | 
           160 | 
             if (rawAPNSInfo) {
  | 
        
        
            | 
            | 
           161 | 
               // TODO(chliangGoogle: Use the new API and secureCoding protocol.
  | 
        
        
            | 
            | 
           162 | 
               @try {
  | 
        
        
            | 
            | 
           163 | 
                 [NSKeyedUnarchiver setClass:[FIRMessagingAPNSInfo class]
  | 
        
        
            | 
            | 
           164 | 
                                forClassName:@"FIRInstanceIDAPNSInfo"];
  | 
        
        
            | 
            | 
           165 | 
           #pragma clang diagnostic push
  | 
        
        
            | 
            | 
           166 | 
           #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  | 
        
        
            | 
            | 
           167 | 
                 APNSInfo = [NSKeyedUnarchiver unarchiveObjectWithData:rawAPNSInfo];
  | 
        
        
            | 
            | 
           168 | 
           #pragma clang diagnostic pop
  | 
        
        
            | 
            | 
           169 | 
               } @catch (NSException *exception) {
  | 
        
        
            | 
            | 
           170 | 
                 FIRMessagingLoggerInfo(kFIRMessagingMessageCodeTokenInfoBadAPNSInfo,
  | 
        
        
            | 
            | 
           171 | 
                                        @"Could not parse raw APNS Info while parsing archived token info.");
  | 
        
        
            | 
            | 
           172 | 
                 APNSInfo = nil;
  | 
        
        
            | 
            | 
           173 | 
               } @finally {
  | 
        
        
            | 
            | 
           174 | 
               }
  | 
        
        
            | 
            | 
           175 | 
             }
  | 
        
        
            | 
            | 
           176 | 
              | 
        
        
            | 
            | 
           177 | 
             id cacheTime = [aDecoder decodeObjectForKey:kFIRInstanceIDCacheTimeKey];
  | 
        
        
            | 
            | 
           178 | 
             if (cacheTime && ![cacheTime isKindOfClass:[NSDate class]]) {
  | 
        
        
            | 
            | 
           179 | 
               return nil;
  | 
        
        
            | 
            | 
           180 | 
             }
  | 
        
        
            | 
            | 
           181 | 
              | 
        
        
            | 
            | 
           182 | 
             self = [super init];
  | 
        
        
            | 
            | 
           183 | 
             if (self) {
  | 
        
        
            | 
            | 
           184 | 
               _authorizedEntity = [authorizedEntity copy];
  | 
        
        
            | 
            | 
           185 | 
               _scope = [scope copy];
  | 
        
        
            | 
            | 
           186 | 
               _token = [token copy];
  | 
        
        
            | 
            | 
           187 | 
               _appVersion = [appVersion copy];
  | 
        
        
            | 
            | 
           188 | 
               _firebaseAppID = [firebaseAppID copy];
  | 
        
        
            | 
            | 
           189 | 
               _APNSInfo = [APNSInfo copy];
  | 
        
        
            | 
            | 
           190 | 
               _cacheTime = cacheTime;
  | 
        
        
            | 
            | 
           191 | 
             }
  | 
        
        
            | 
            | 
           192 | 
             return self;
  | 
        
        
            | 
            | 
           193 | 
           }
  | 
        
        
            | 
            | 
           194 | 
              | 
        
        
            | 
            | 
           195 | 
           - (void)encodeWithCoder:(NSCoder *)aCoder {
  | 
        
        
            | 
            | 
           196 | 
             [aCoder encodeObject:self.authorizedEntity forKey:kFIRInstanceIDAuthorizedEntityKey];
  | 
        
        
            | 
            | 
           197 | 
             [aCoder encodeObject:self.scope forKey:kFIRInstanceIDScopeKey];
  | 
        
        
            | 
            | 
           198 | 
             [aCoder encodeObject:self.token forKey:kFIRInstanceIDTokenKey];
  | 
        
        
            | 
            | 
           199 | 
             [aCoder encodeObject:self.appVersion forKey:kFIRInstanceIDAppVersionKey];
  | 
        
        
            | 
            | 
           200 | 
             [aCoder encodeObject:self.firebaseAppID forKey:kFIRInstanceIDFirebaseAppIDKey];
  | 
        
        
            | 
            | 
           201 | 
             NSData *rawAPNSInfo;
  | 
        
        
            | 
            | 
           202 | 
             if (self.APNSInfo) {
  | 
        
        
            | 
            | 
           203 | 
               // TODO(chliangGoogle: Use the new API and secureCoding protocol.
  | 
        
        
            | 
            | 
           204 | 
               [NSKeyedArchiver setClassName:@"FIRInstanceIDAPNSInfo" forClass:[FIRMessagingAPNSInfo class]];
  | 
        
        
            | 
            | 
           205 | 
           #pragma clang diagnostic push
  | 
        
        
            | 
            | 
           206 | 
           #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  | 
        
        
            | 
            | 
           207 | 
               rawAPNSInfo = [NSKeyedArchiver archivedDataWithRootObject:self.APNSInfo];
  | 
        
        
            | 
            | 
           208 | 
           #pragma clang diagnostic pop
  | 
        
        
            | 
            | 
           209 | 
              | 
        
        
            | 
            | 
           210 | 
               [aCoder encodeObject:rawAPNSInfo forKey:kFIRInstanceIDAPNSInfoKey];
  | 
        
        
            | 
            | 
           211 | 
             }
  | 
        
        
            | 
            | 
           212 | 
             [aCoder encodeObject:self.cacheTime forKey:kFIRInstanceIDCacheTimeKey];
  | 
        
        
            | 
            | 
           213 | 
           }
  | 
        
        
            | 
            | 
           214 | 
              | 
        
        
            | 
            | 
           215 | 
           @end
  |