No Description

FIRInstanceIDTokenStore.m 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. #import "FIRInstanceIDTokenStore.h"
  17. #import "FIRInstanceIDAuthKeyChain.h"
  18. #import "FIRInstanceIDConstants.h"
  19. #import "FIRInstanceIDLogger.h"
  20. #import "FIRInstanceIDTokenInfo.h"
  21. #import "FIRInstanceIDUtilities.h"
  22. static NSString *const kFIRInstanceIDTokenKeychainId = @"com.google.iid-tokens";
  23. @interface FIRInstanceIDTokenStore ()
  24. @property(nonatomic, readwrite, strong) FIRInstanceIDAuthKeychain *keychain;
  25. @end
  26. @implementation FIRInstanceIDTokenStore
  27. + (instancetype)defaultStore {
  28. FIRInstanceIDAuthKeychain *tokenKeychain =
  29. [[FIRInstanceIDAuthKeychain alloc] initWithIdentifier:kFIRInstanceIDTokenKeychainId];
  30. return [[FIRInstanceIDTokenStore alloc] initWithKeychain:tokenKeychain];
  31. }
  32. - (instancetype)initWithKeychain:(FIRInstanceIDAuthKeychain *)keychain {
  33. self = [super init];
  34. if (self) {
  35. _keychain = keychain;
  36. }
  37. return self;
  38. }
  39. #pragma mark - Get
  40. + (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {
  41. return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope];
  42. }
  43. - (nullable FIRInstanceIDTokenInfo *)tokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity
  44. scope:(NSString *)scope {
  45. NSString *account = FIRInstanceIDAppIdentifier();
  46. NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope];
  47. NSData *item = [self.keychain dataForService:service account:account];
  48. if (!item) {
  49. return nil;
  50. }
  51. // Token infos created from legacy storage don't have appVersion, firebaseAppID, or APNSInfo.
  52. FIRInstanceIDTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item];
  53. return tokenInfo;
  54. }
  55. - (NSArray<FIRInstanceIDTokenInfo *> *)cachedTokenInfos {
  56. NSString *account = FIRInstanceIDAppIdentifier();
  57. NSArray<NSData *> *items =
  58. [self.keychain itemsMatchingService:kFIRInstanceIDKeychainWildcardIdentifier account:account];
  59. NSMutableArray<FIRInstanceIDTokenInfo *> *tokenInfos =
  60. [NSMutableArray arrayWithCapacity:items.count];
  61. for (NSData *item in items) {
  62. FIRInstanceIDTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item];
  63. if (tokenInfo) {
  64. [tokenInfos addObject:tokenInfo];
  65. }
  66. }
  67. return tokenInfos;
  68. }
  69. + (nullable FIRInstanceIDTokenInfo *)tokenInfoFromKeychainItem:(NSData *)item {
  70. // Check if it is saved as an archived FIRInstanceIDTokenInfo, otherwise return nil.
  71. FIRInstanceIDTokenInfo *tokenInfo = nil;
  72. // NOTE: Passing in nil to unarchiveObjectWithData will result in an iOS error logged
  73. // in the console on iOS 10 and below. Avoid by checking item.data's existence.
  74. if (item) {
  75. // TODO(chliangGoogle: Use the new API and secureCoding protocol.
  76. @try {
  77. #pragma clang diagnostic push
  78. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  79. tokenInfo = [NSKeyedUnarchiver unarchiveObjectWithData:item];
  80. #pragma clang diagnostic pop
  81. } @catch (NSException *exception) {
  82. FIRInstanceIDLoggerDebug(kFIRInstanceIDMessageCodeTokenStoreExceptionUnarchivingTokenInfo,
  83. @"Unable to parse token info from Keychain item; item was in an "
  84. @"invalid format");
  85. tokenInfo = nil;
  86. } @finally {
  87. }
  88. }
  89. return tokenInfo;
  90. }
  91. #pragma mark - Save
  92. // Token Infos will be saved under these Keychain keys:
  93. // Account: <Main App Bundle ID> (e.g. com.mycompany.myapp)
  94. // Service: <Sender ID>:<Scope> (e.g. 1234567890:*)
  95. - (void)saveTokenInfo:(FIRInstanceIDTokenInfo *)tokenInfo
  96. handler:(void (^)(NSError *))handler { // Keep the cachetime up-to-date.
  97. tokenInfo.cacheTime = [NSDate date];
  98. // Always write to the Keychain, so that the cacheTime is up-to-date.
  99. NSData *tokenInfoData;
  100. // TODO(chliangGoogle: Use the new API and secureCoding protocol.
  101. #pragma clang diagnostic push
  102. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  103. tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo];
  104. #pragma clang diagnostic pop
  105. NSString *account = FIRInstanceIDAppIdentifier();
  106. NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntity
  107. scope:tokenInfo.scope];
  108. [self.keychain setData:tokenInfoData
  109. forService:service
  110. accessibility:NULL
  111. account:account
  112. handler:handler];
  113. }
  114. #pragma mark - Delete
  115. - (void)removeTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity
  116. scope:(nonnull NSString *)scope {
  117. NSString *account = FIRInstanceIDAppIdentifier();
  118. NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope];
  119. [self.keychain removeItemsMatchingService:service account:account handler:nil];
  120. }
  121. - (void)removeAllTokensWithHandler:(void (^)(NSError *error))handler {
  122. NSString *account = FIRInstanceIDAppIdentifier();
  123. [self.keychain removeItemsMatchingService:kFIRInstanceIDKeychainWildcardIdentifier
  124. account:account
  125. handler:handler];
  126. }
  127. @end