FIRMessagingTokenOperation.m 7.8 KB

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