Без опису

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 "FIRInstanceIDTokenOperation.h"
  17. #import "FIRInstanceIDCheckinPreferences.h"
  18. #import "FIRInstanceIDKeyPair.h"
  19. #import "FIRInstanceIDKeyPairUtilities.h"
  20. #import "FIRInstanceIDLogger.h"
  21. #import "FIRInstanceIDURLQueryItem.h"
  22. #import "FIRInstanceIDUtilities.h"
  23. #import "NSError+FIRInstanceID.h"
  24. static const NSInteger kFIRInstanceIDPlatformVersionIOS = 2;
  25. static NSString *const kFIRInstanceIDParamInstanceID = @"appid";
  26. // Scope parameter that defines the service using the token
  27. static NSString *const kFIRInstanceIDParamScope = @"X-scope";
  28. // Defines the SDK version
  29. static NSString *const kFIRInstanceIDParamFCMLibVersion = @"X-cliv";
  30. @interface FIRInstanceIDTokenOperation () {
  31. BOOL _isFinished;
  32. BOOL _isExecuting;
  33. }
  34. @property(nonatomic, readwrite, strong) FIRInstanceIDCheckinPreferences *checkinPreferences;
  35. @property(nonatomic, readwrite, strong) FIRInstanceIDKeyPair *keyPair;
  36. @property(atomic, strong) NSURLSessionDataTask *dataTask;
  37. @property(readonly, strong)
  38. NSMutableArray<FIRInstanceIDTokenOperationCompletion> *completionHandlers;
  39. // For testing only
  40. @property(nonatomic, readwrite, copy) FIRInstanceIDURLRequestTestBlock testBlock;
  41. @end
  42. @implementation FIRInstanceIDTokenOperation
  43. + (NSURLSession *)sharedURLSession {
  44. static NSURLSession *tokenOperationSharedSession;
  45. static dispatch_once_t onceToken;
  46. dispatch_once(&onceToken, ^{
  47. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  48. config.timeoutIntervalForResource = 60.0f; // 1 minute
  49. tokenOperationSharedSession = [NSURLSession sessionWithConfiguration:config];
  50. tokenOperationSharedSession.sessionDescription = @"com.google.iid.tokens.session";
  51. });
  52. return tokenOperationSharedSession;
  53. }
  54. - (instancetype)initWithAction:(FIRInstanceIDTokenAction)action
  55. forAuthorizedEntity:(NSString *)authorizedEntity
  56. scope:(NSString *)scope
  57. options:(NSDictionary<NSString *, NSString *> *)options
  58. checkinPreferences:(FIRInstanceIDCheckinPreferences *)checkinPreferences
  59. keyPair:(FIRInstanceIDKeyPair *)keyPair {
  60. self = [super init];
  61. if (self) {
  62. _action = action;
  63. _authorizedEntity = [authorizedEntity copy];
  64. _scope = [scope copy];
  65. _options = [options copy];
  66. _checkinPreferences = checkinPreferences;
  67. _keyPair = keyPair;
  68. _completionHandlers = [NSMutableArray array];
  69. _isExecuting = NO;
  70. _isFinished = NO;
  71. }
  72. return self;
  73. }
  74. - (void)dealloc {
  75. _testBlock = nil;
  76. _authorizedEntity = nil;
  77. _scope = nil;
  78. _options = nil;
  79. _checkinPreferences = nil;
  80. _keyPair = nil;
  81. [_completionHandlers removeAllObjects];
  82. _completionHandlers = nil;
  83. }
  84. - (void)addCompletionHandler:(FIRInstanceIDTokenOperationCompletion)handler {
  85. [self.completionHandlers addObject:handler];
  86. }
  87. - (BOOL)isAsynchronous {
  88. return YES;
  89. }
  90. - (BOOL)isExecuting {
  91. return _isExecuting;
  92. }
  93. - (void)setExecuting:(BOOL)executing {
  94. [self willChangeValueForKey:@"isExecuting"];
  95. _isExecuting = executing;
  96. [self didChangeValueForKey:@"isExecuting"];
  97. }
  98. - (BOOL)isFinished {
  99. return _isFinished;
  100. }
  101. - (void)setFinished:(BOOL)finished {
  102. [self willChangeValueForKey:@"isFinished"];
  103. _isFinished = finished;
  104. [self didChangeValueForKey:@"isFinished"];
  105. }
  106. - (void)start {
  107. if (self.isCancelled) {
  108. [self finishWithResult:FIRInstanceIDTokenOperationCancelled token:nil error:nil];
  109. return;
  110. }
  111. // Quickly validate whether or not the operation has all it needs to begin
  112. BOOL checkinfoAvailable = [self.checkinPreferences hasCheckinInfo];
  113. if (!checkinfoAvailable) {
  114. FIRInstanceIDErrorCode errorCode = kFIRInstanceIDErrorCodeRegistrarFailedToCheckIn;
  115. [self finishWithResult:FIRInstanceIDTokenOperationError
  116. token:nil
  117. error:[NSError errorWithFIRInstanceIDErrorCode:errorCode]];
  118. return;
  119. }
  120. [self setExecuting:YES];
  121. [self performTokenOperation];
  122. }
  123. - (void)finishWithResult:(FIRInstanceIDTokenOperationResult)result
  124. token:(nullable NSString *)token
  125. error:(nullable NSError *)error {
  126. // Add a check to prevent this finish from being called more than once.
  127. if (self.isFinished) {
  128. return;
  129. }
  130. self.dataTask = nil;
  131. _result = result;
  132. // TODO(chliangGoogle): Call these in the main thread?
  133. for (FIRInstanceIDTokenOperationCompletion completionHandler in self.completionHandlers) {
  134. completionHandler(result, token, error);
  135. }
  136. [self setExecuting:NO];
  137. [self setFinished:YES];
  138. }
  139. - (void)cancel {
  140. [super cancel];
  141. [self.dataTask cancel];
  142. [self finishWithResult:FIRInstanceIDTokenOperationCancelled token:nil error:nil];
  143. }
  144. - (void)performTokenOperation {
  145. }
  146. #pragma mark - Request Construction
  147. + (NSMutableURLRequest *)requestWithAuthHeader:(NSString *)authHeaderString {
  148. NSURL *url = [NSURL URLWithString:FIRInstanceIDRegisterServer()];
  149. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  150. // Add HTTP headers
  151. [request setValue:authHeaderString forHTTPHeaderField:@"Authorization"];
  152. [request setValue:FIRInstanceIDAppIdentifier() forHTTPHeaderField:@"app"];
  153. request.HTTPMethod = @"POST";
  154. return request;
  155. }
  156. + (NSMutableArray<FIRInstanceIDURLQueryItem *> *)standardQueryItemsWithDeviceID:(NSString *)deviceID
  157. scope:(NSString *)scope {
  158. NSMutableArray<FIRInstanceIDURLQueryItem *> *queryItems = [NSMutableArray arrayWithCapacity:8];
  159. // E.g. X-osv=10.2.1
  160. NSString *systemVersion = FIRInstanceIDOperatingSystemVersion();
  161. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"X-osv" value:systemVersion]];
  162. // E.g. device=
  163. if (deviceID) {
  164. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"device" value:deviceID]];
  165. }
  166. // E.g. X-scope=fcm
  167. if (scope) {
  168. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamScope
  169. value:scope]];
  170. }
  171. // E.g. plat=2
  172. NSString *platform = [NSString stringWithFormat:@"%ld", (long)kFIRInstanceIDPlatformVersionIOS];
  173. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"plat" value:platform]];
  174. // E.g. app=com.myapp.foo
  175. NSString *appIdentifier = FIRInstanceIDAppIdentifier();
  176. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"app" value:appIdentifier]];
  177. // E.g. app_ver=1.5
  178. NSString *appVersion = FIRInstanceIDCurrentAppVersion();
  179. [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"app_ver" value:appVersion]];
  180. // E.g. X-cliv=fiid-1.2.3
  181. NSString *fcmLibraryVersion =
  182. [NSString stringWithFormat:@"fiid-%@", FIRInstanceIDCurrentGCMVersion()];
  183. if (fcmLibraryVersion.length) {
  184. FIRInstanceIDURLQueryItem *gcmLibVersion =
  185. [FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamFCMLibVersion
  186. value:fcmLibraryVersion];
  187. [queryItems addObject:gcmLibVersion];
  188. }
  189. return queryItems;
  190. }
  191. - (NSArray<FIRInstanceIDURLQueryItem *> *)queryItemsWithKeyPair:(FIRInstanceIDKeyPair *)keyPair {
  192. NSMutableArray<FIRInstanceIDURLQueryItem *> *items = [NSMutableArray arrayWithCapacity:3];
  193. // appid=
  194. NSString *instanceID = FIRInstanceIDAppIdentity(keyPair);
  195. [items addObject:[FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamInstanceID
  196. value:instanceID]];
  197. return items;
  198. }
  199. #pragma mark - HTTP Header
  200. + (NSString *)HTTPAuthHeaderFromCheckin:(FIRInstanceIDCheckinPreferences *)checkin {
  201. NSString *deviceID = checkin.deviceID;
  202. NSString *secret = checkin.secretToken;
  203. return [NSString stringWithFormat:@"AidLogin %@:%@", deviceID, secret];
  204. }
  205. @end