AutorÃa | Ultima modificación | Ver Log |
/** Copyright 2019 Google** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h"#import "FirebaseMessaging/Sources/FIRMessagingConstants.h"#import "FirebaseMessaging/Sources/FIRMessagingLogger.h"#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h"#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h"#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h"static NSString *const kFIRMessagingTokenKeychainId = @"com.google.iid-tokens";@interface FIRMessagingTokenStore ()@property(nonatomic, readwrite, strong) FIRMessagingAuthKeychain *keychain;@end@implementation FIRMessagingTokenStore- (instancetype)init {self = [super init];if (self) {_keychain = [[FIRMessagingAuthKeychain alloc] initWithIdentifier:kFIRMessagingTokenKeychainId];}return self;}#pragma mark - Get+ (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope];}- (nullable FIRMessagingTokenInfo *)tokenInfoWithAuthorizedEntity:(NSString *)authorizedEntityscope:(NSString *)scope {// TODO(chliangGoogle): If we don't have the token plist we should delete all the tokens from// the keychain. This is because not having the plist signifies a backup and restore operation.// In case the keychain has any tokens these would now be stale and therefore should be// deleted.if (![authorizedEntity length] || ![scope length]) {return nil;}NSString *account = FIRMessagingAppIdentifier();NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope];NSData *item = [self.keychain dataForService:service account:account];if (!item) {return nil;}// Token infos created from legacy storage don't have appVersion, firebaseAppID, or APNSInfo.FIRMessagingTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item];return tokenInfo;}- (NSArray<FIRMessagingTokenInfo *> *)cachedTokenInfos {NSString *account = FIRMessagingAppIdentifier();NSArray<NSData *> *items =[self.keychain itemsMatchingService:kFIRMessagingKeychainWildcardIdentifier account:account];NSMutableArray<FIRMessagingTokenInfo *> *tokenInfos =[NSMutableArray arrayWithCapacity:items.count];for (NSData *item in items) {FIRMessagingTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item];if (tokenInfo) {[tokenInfos addObject:tokenInfo];}}return tokenInfos;}+ (nullable FIRMessagingTokenInfo *)tokenInfoFromKeychainItem:(NSData *)item {// Check if it is saved as an archived FIRMessagingTokenInfo, otherwise return nil.FIRMessagingTokenInfo *tokenInfo = nil;// NOTE: Passing in nil to unarchiveObjectWithData will result in an iOS error logged// in the console on iOS 10 and below. Avoid by checking item.data's existence.if (item) {// TODO(chliangGoogle: Use the new API and secureCoding protocol.@try {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"[NSKeyedUnarchiver setClass:[FIRMessagingTokenInfo class]forClassName:@"FIRInstanceIDTokenInfo"];tokenInfo = [NSKeyedUnarchiver unarchiveObjectWithData:item];#pragma clang diagnostic pop} @catch (NSException *exception) {FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenStoreExceptionUnarchivingTokenInfo,@"Unable to parse token info from Keychain item; item was in an "@"invalid format");tokenInfo = nil;} @finally {}}return tokenInfo;}#pragma mark - Save// Token Infos will be saved under these Keychain keys:// Account: <Main App Bundle ID> (e.g. com.mycompany.myapp)// Service: <Sender ID>:<Scope> (e.g. 1234567890:*)- (void)saveTokenInfo:(FIRMessagingTokenInfo *)tokenInfohandler:(void (^)(NSError *))handler { // Keep the cachetime up-to-date.tokenInfo.cacheTime = [NSDate date];// Always write to the Keychain, so that the cacheTime is up-to-date.NSData *tokenInfoData;// TODO(chliangGoogle: Use the new API and secureCoding protocol.[NSKeyedArchiver setClassName:@"FIRInstanceIDTokenInfo" forClass:[FIRMessagingTokenInfo class]];#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo];#pragma clang diagnostic popNSString *account = FIRMessagingAppIdentifier();NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntityscope:tokenInfo.scope];[self.keychain setData:tokenInfoData forService:service account:account handler:handler];}- (void)saveTokenInfoInCache:(FIRMessagingTokenInfo *)tokenInfo {tokenInfo.cacheTime = [NSDate date];// TODO(chliangGoogle): Use the new API and secureCoding protocol.// Always write to the Keychain, so that the cacheTime is up-to-date.NSData *tokenInfoData;[NSKeyedArchiver setClassName:@"FIRInstanceIDTokenInfo" forClass:[FIRMessagingTokenInfo class]];#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo];#pragma clang diagnostic popNSString *account = FIRMessagingAppIdentifier();NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntityscope:tokenInfo.scope];[self.keychain setCacheData:tokenInfoData forService:service account:account];}#pragma mark - Delete- (void)removeTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntityscope:(nonnull NSString *)scope {if (![authorizedEntity length] || ![scope length]) {FIRMessagingLoggerError(kFIRMessagingMessageCodeStore012,@"Will not delete token with invalid entity: %@, scope: %@",authorizedEntity, scope);return;}NSString *account = FIRMessagingAppIdentifier();NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope];[self.keychain removeItemsMatchingService:service account:account handler:nil];}- (void)removeAllTokensWithHandler:(void (^)(NSError *error))handler {NSString *account = FIRMessagingAppIdentifier();[self.keychain removeItemsMatchingService:kFIRMessagingKeychainWildcardIdentifieraccount:accounthandler:handler];}@end