FIRMessagingTokenOperation.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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 "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h"
  17. #import <GoogleUtilities/GULAppEnvironmentUtil.h>
  18. #import "FirebaseCore/Extension/FIRHeartbeatLogger.h"
  19. #import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
  20. #import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
  21. #import "FirebaseMessaging/Sources/FIRMessagingUtilities.h"
  22. #import "FirebaseMessaging/Sources/FIRMessaging_Private.h"
  23. #import "FirebaseMessaging/Sources/NSError+FIRMessaging.h"
  24. #import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h"
  25. static const NSInteger kFIRMessagingPlatformVersionIOS = 2;
  26. // Scope parameter that defines the service using the token
  27. static NSString *const kFIRMessagingParamScope = @"X-scope";
  28. // Defines the SDK version
  29. static NSString *const kFIRMessagingParamFCMLibVersion = @"X-cliv";
  30. @interface FIRMessagingTokenOperation () {
  31. BOOL _isFinished;
  32. BOOL _isExecuting;
  33. NSMutableArray<FIRMessagingTokenOperationCompletion> *_completionHandlers;
  34. FIRMessagingCheckinPreferences *_checkinPreferences;
  35. }
  36. @property(nonatomic, readwrite, strong) NSString *instanceID;
  37. @property(atomic, strong, nullable) NSString *FISAuthToken;
  38. @end
  39. @implementation FIRMessagingTokenOperation
  40. - (instancetype)initWithAction:(FIRMessagingTokenAction)action
  41. forAuthorizedEntity:(NSString *)authorizedEntity
  42. scope:(NSString *)scope
  43. options:(NSDictionary<NSString *, NSString *> *)options
  44. checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences
  45. instanceID:(NSString *)instanceID
  46. heartbeatLogger:(id<FIRHeartbeatLoggerProtocol>)heartbeatLogger {
  47. self = [super init];
  48. if (self) {
  49. _action = action;
  50. _authorizedEntity = [authorizedEntity copy];
  51. _scope = [scope copy];
  52. _options = [options copy];
  53. _checkinPreferences = checkinPreferences;
  54. _instanceID = instanceID;
  55. _completionHandlers = [[NSMutableArray alloc] init];
  56. _heartbeatLogger = heartbeatLogger;
  57. _isExecuting = NO;
  58. _isFinished = NO;
  59. }
  60. return self;
  61. }
  62. - (void)dealloc {
  63. [_completionHandlers removeAllObjects];
  64. }
  65. - (void)addCompletionHandler:(FIRMessagingTokenOperationCompletion)handler {
  66. [_completionHandlers addObject:[handler copy]];
  67. }
  68. - (BOOL)isAsynchronous {
  69. return YES;
  70. }
  71. - (BOOL)isExecuting {
  72. return _isExecuting;
  73. }
  74. - (void)setExecuting:(BOOL)executing {
  75. [self willChangeValueForKey:@"isExecuting"];
  76. _isExecuting = executing;
  77. [self didChangeValueForKey:@"isExecuting"];
  78. }
  79. - (BOOL)isFinished {
  80. return _isFinished;
  81. }
  82. - (void)setFinished:(BOOL)finished {
  83. [self willChangeValueForKey:@"isFinished"];
  84. _isFinished = finished;
  85. [self didChangeValueForKey:@"isFinished"];
  86. }
  87. - (void)start {
  88. if (self.isCancelled) {
  89. [self finishWithResult:FIRMessagingTokenOperationCancelled token:nil error:nil];
  90. return;
  91. }
  92. // Quickly validate whether or not the operation has all it needs to begin
  93. BOOL checkinfoAvailable = [self.checkinPreferences hasCheckinInfo];
  94. if (!checkinfoAvailable) {
  95. FIRMessagingErrorCode errorCode = kFIRMessagingErrorCodeRegistrarFailedToCheckIn;
  96. [self finishWithResult:FIRMessagingTokenOperationError
  97. token:nil
  98. error:[NSError messagingErrorWithCode:errorCode
  99. failureReason:
  100. @"Failed to checkin before token registration."]];
  101. return;
  102. }
  103. [self setExecuting:YES];
  104. [[FIRInstallations installations]
  105. authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
  106. NSError *_Nullable error) {
  107. if (tokenResult.authToken.length > 0) {
  108. self.FISAuthToken = tokenResult.authToken;
  109. [self performTokenOperation];
  110. } else {
  111. [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error];
  112. }
  113. }];
  114. }
  115. - (void)finishWithResult:(FIRMessagingTokenOperationResult)result
  116. token:(nullable NSString *)token
  117. error:(nullable NSError *)error {
  118. // Add a check to prevent this finish from being called more than once.
  119. if (self.isFinished) {
  120. return;
  121. }
  122. self.dataTask = nil;
  123. _result = result;
  124. for (FIRMessagingTokenOperationCompletion completionHandler in _completionHandlers) {
  125. completionHandler(result, token, error);
  126. }
  127. [self setExecuting:NO];
  128. [self setFinished:YES];
  129. }
  130. - (void)cancel {
  131. [super cancel];
  132. [self.dataTask cancel];
  133. [self finishWithResult:FIRMessagingTokenOperationCancelled token:nil error:nil];
  134. }
  135. - (void)performTokenOperation {
  136. }
  137. - (NSMutableURLRequest *)tokenRequest {
  138. NSString *authHeader =
  139. [FIRMessagingTokenOperation HTTPAuthHeaderFromCheckin:self.checkinPreferences];
  140. return [[self class] requestWithAuthHeader:authHeader FISAuthToken:self.FISAuthToken];
  141. }
  142. #pragma mark - Request Construction
  143. + (NSMutableURLRequest *)requestWithAuthHeader:(NSString *)authHeaderString
  144. FISAuthToken:(NSString *)FISAuthToken {
  145. NSURL *url = [NSURL URLWithString:FIRMessagingTokenRegisterServer()];
  146. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  147. // Add HTTP headers
  148. [request setValue:authHeaderString forHTTPHeaderField:@"Authorization"];
  149. [request setValue:FIRMessagingAppIdentifier() forHTTPHeaderField:@"app"];
  150. if (FISAuthToken) {
  151. [request setValue:FISAuthToken forHTTPHeaderField:@"x-goog-firebase-installations-auth"];
  152. }
  153. request.HTTPMethod = @"POST";
  154. return request;
  155. }
  156. + (NSMutableArray<NSURLQueryItem *> *)standardQueryItemsWithDeviceID:(NSString *)deviceID
  157. scope:(NSString *)scope {
  158. NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray arrayWithCapacity:8];
  159. // E.g. X-osv=10.2.1
  160. NSString *systemVersion = [GULAppEnvironmentUtil systemVersion];
  161. [queryItems addObject:[NSURLQueryItem queryItemWithName:@"X-osv" value:systemVersion]];
  162. // E.g. device=
  163. if (deviceID) {
  164. [queryItems addObject:[NSURLQueryItem queryItemWithName:@"device" value:deviceID]];
  165. }
  166. // E.g. X-scope=fcm
  167. if (scope) {
  168. [queryItems addObject:[NSURLQueryItem queryItemWithName:kFIRMessagingParamScope value:scope]];
  169. }
  170. // E.g. plat=2
  171. NSString *platform = [NSString stringWithFormat:@"%ld", (long)kFIRMessagingPlatformVersionIOS];
  172. [queryItems addObject:[NSURLQueryItem queryItemWithName:@"plat" value:platform]];
  173. // E.g. app=com.myapp.foo
  174. NSString *appIdentifier = FIRMessagingAppIdentifier();
  175. [queryItems addObject:[NSURLQueryItem queryItemWithName:@"app" value:appIdentifier]];
  176. // E.g. app_ver=1.5
  177. NSString *appVersion = FIRMessagingCurrentAppVersion();
  178. [queryItems addObject:[NSURLQueryItem queryItemWithName:@"app_ver" value:appVersion]];
  179. // E.g. X-cliv=fiid-1.2.3
  180. NSString *fcmLibraryVersion =
  181. [NSString stringWithFormat:@"fiid-%@", [FIRMessaging FIRMessagingSDKVersion]];
  182. if (fcmLibraryVersion.length) {
  183. NSURLQueryItem *gcmLibVersion =
  184. [NSURLQueryItem queryItemWithName:kFIRMessagingParamFCMLibVersion value:fcmLibraryVersion];
  185. [queryItems addObject:gcmLibVersion];
  186. }
  187. return queryItems;
  188. }
  189. #pragma mark - Header
  190. + (NSString *)HTTPAuthHeaderFromCheckin:(FIRMessagingCheckinPreferences *)checkin {
  191. NSString *deviceID = checkin.deviceID;
  192. NSString *secret = checkin.secretToken;
  193. return [NSString stringWithFormat:@"AidLogin %@:%@", deviceID, secret];
  194. }
  195. @end