FIRInstallationsIIDTokenStore.m 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h"
  17. #if __has_include(<FBLPromises/FBLPromises.h>)
  18. #import <FBLPromises/FBLPromises.h>
  19. #else
  20. #import "FBLPromises.h"
  21. #endif
  22. #import <GoogleUtilities/GULKeychainUtils.h>
  23. #import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h"
  24. static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens";
  25. @interface FIRInstallationsIIDTokenInfo : NSObject <NSSecureCoding>
  26. @property(nonatomic, nullable, copy) NSString *token;
  27. @end
  28. @implementation FIRInstallationsIIDTokenInfo
  29. + (BOOL)supportsSecureCoding {
  30. return YES;
  31. }
  32. - (void)encodeWithCoder:(nonnull NSCoder *)coder {
  33. }
  34. - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
  35. self = [super init];
  36. if (self) {
  37. _token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"];
  38. }
  39. return self;
  40. }
  41. @end
  42. @interface FIRInstallationsIIDTokenStore ()
  43. @property(nonatomic, readonly) NSString *GCMSenderID;
  44. @end
  45. @implementation FIRInstallationsIIDTokenStore
  46. - (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID {
  47. self = [super init];
  48. if (self) {
  49. _GCMSenderID = GCMSenderID;
  50. }
  51. return self;
  52. }
  53. - (FBLPromise<NSString *> *)existingIIDDefaultToken {
  54. return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
  55. do:^id _Nullable {
  56. return [self IIDDefaultTokenData];
  57. }] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
  58. then:^id _Nullable(NSData *_Nullable keychainData) {
  59. return [self IIDCheckinWithData:keychainData];
  60. }];
  61. }
  62. - (FBLPromise<NSString *> *)IIDCheckinWithData:(NSData *)data {
  63. FBLPromise<NSString *> *resultPromise = [FBLPromise pendingPromise];
  64. NSError *archiverError;
  65. NSKeyedUnarchiver *unarchiver;
  66. if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) {
  67. unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError];
  68. } else {
  69. @try {
  70. #pragma clang diagnostic push
  71. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  72. unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
  73. #pragma clang diagnostic pop
  74. } @catch (NSException *exception) {
  75. archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception];
  76. }
  77. }
  78. if (!unarchiver) {
  79. NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
  80. [resultPromise reject:error];
  81. return resultPromise;
  82. }
  83. [unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"];
  84. FIRInstallationsIIDTokenInfo *IIDTokenInfo =
  85. [unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class]
  86. forKey:NSKeyedArchiveRootObjectKey];
  87. if (IIDTokenInfo.token.length < 1) {
  88. [resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]];
  89. return resultPromise;
  90. }
  91. [resultPromise fulfill:IIDTokenInfo.token];
  92. return resultPromise;
  93. }
  94. - (FBLPromise<NSData *> *)IIDDefaultTokenData {
  95. FBLPromise<NSData *> *resultPromise = [FBLPromise pendingPromise];
  96. NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery];
  97. NSError *error;
  98. NSData *data = [GULKeychainUtils getItemWithQuery:keychainQuery error:&error];
  99. if (data) {
  100. [resultPromise fulfill:data];
  101. return resultPromise;
  102. } else {
  103. NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
  104. [resultPromise reject:outError];
  105. return resultPromise;
  106. }
  107. }
  108. - (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery {
  109. NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword};
  110. NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query];
  111. finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId;
  112. NSString *account = [self IIDAppIdentifier];
  113. if ([account length]) {
  114. finalQuery[(__bridge NSString *)kSecAttrAccount] = account;
  115. }
  116. finalQuery[(__bridge NSString *)kSecAttrService] =
  117. [self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"];
  118. return finalQuery;
  119. }
  120. - (NSString *)IIDAppIdentifier {
  121. return [[NSBundle mainBundle] bundleIdentifier] ?: @"";
  122. }
  123. - (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {
  124. return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope];
  125. }
  126. @end