| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /*
- * Copyright 2019 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import "FIRInstanceIDTokenOperation.h"
- #import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
- #import "FIRInstanceIDCheckinPreferences.h"
- #import "FIRInstanceIDLogger.h"
- #import "FIRInstanceIDURLQueryItem.h"
- #import "FIRInstanceIDUtilities.h"
- #import "NSError+FIRInstanceID.h"
- static const NSInteger kFIRInstanceIDPlatformVersionIOS = 2;
- static NSString *const kFIRInstanceIDParamInstanceID = @"appid";
- // Scope parameter that defines the service using the token
- static NSString *const kFIRInstanceIDParamScope = @"X-scope";
- // Defines the SDK version
- static NSString *const kFIRInstanceIDParamFCMLibVersion = @"X-cliv";
- @interface FIRInstanceIDTokenOperation () {
- BOOL _isFinished;
- BOOL _isExecuting;
- }
- @property(nonatomic, readwrite, strong) FIRInstanceIDCheckinPreferences *checkinPreferences;
- @property(nonatomic, readwrite, strong) NSString *instanceID;
- @property(atomic, strong) NSURLSessionDataTask *dataTask;
- @property(readonly, strong)
- NSMutableArray<FIRInstanceIDTokenOperationCompletion> *completionHandlers;
- @property(atomic, strong, nullable) NSString *FISAuthToken;
- // For testing only
- @property(nonatomic, readwrite, copy) FIRInstanceIDURLRequestTestBlock testBlock;
- @end
- @implementation FIRInstanceIDTokenOperation
- + (NSURLSession *)sharedURLSession {
- static NSURLSession *tokenOperationSharedSession;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
- config.timeoutIntervalForResource = 60.0f; // 1 minute
- tokenOperationSharedSession = [NSURLSession sessionWithConfiguration:config];
- tokenOperationSharedSession.sessionDescription = @"com.google.iid.tokens.session";
- });
- return tokenOperationSharedSession;
- }
- - (instancetype)initWithAction:(FIRInstanceIDTokenAction)action
- forAuthorizedEntity:(NSString *)authorizedEntity
- scope:(NSString *)scope
- options:(NSDictionary<NSString *, NSString *> *)options
- checkinPreferences:(FIRInstanceIDCheckinPreferences *)checkinPreferences
- instanceID:(NSString *)instanceID {
- self = [super init];
- if (self) {
- _action = action;
- _authorizedEntity = [authorizedEntity copy];
- _scope = [scope copy];
- _options = [options copy];
- _checkinPreferences = checkinPreferences;
- _instanceID = instanceID;
- _completionHandlers = [NSMutableArray array];
- _isExecuting = NO;
- _isFinished = NO;
- }
- return self;
- }
- - (void)dealloc {
- _testBlock = nil;
- _authorizedEntity = nil;
- _scope = nil;
- _options = nil;
- _checkinPreferences = nil;
- _instanceID = nil;
- [_completionHandlers removeAllObjects];
- _completionHandlers = nil;
- }
- - (void)addCompletionHandler:(FIRInstanceIDTokenOperationCompletion)handler {
- [self.completionHandlers addObject:handler];
- }
- - (BOOL)isAsynchronous {
- return YES;
- }
- - (BOOL)isExecuting {
- return _isExecuting;
- }
- - (void)setExecuting:(BOOL)executing {
- [self willChangeValueForKey:@"isExecuting"];
- _isExecuting = executing;
- [self didChangeValueForKey:@"isExecuting"];
- }
- - (BOOL)isFinished {
- return _isFinished;
- }
- - (void)setFinished:(BOOL)finished {
- [self willChangeValueForKey:@"isFinished"];
- _isFinished = finished;
- [self didChangeValueForKey:@"isFinished"];
- }
- - (void)start {
- if (self.isCancelled) {
- [self finishWithResult:FIRInstanceIDTokenOperationCancelled token:nil error:nil];
- return;
- }
- // Quickly validate whether or not the operation has all it needs to begin
- BOOL checkinfoAvailable = [self.checkinPreferences hasCheckinInfo];
- if (!checkinfoAvailable) {
- FIRInstanceIDErrorCode errorCode = kFIRInstanceIDErrorCodeRegistrarFailedToCheckIn;
- [self finishWithResult:FIRInstanceIDTokenOperationError
- token:nil
- error:[NSError errorWithFIRInstanceIDErrorCode:errorCode]];
- return;
- }
- [self setExecuting:YES];
- [[FIRInstallations installations]
- authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult,
- NSError *_Nullable error) {
- if (tokenResult.authToken.length > 0) {
- self.FISAuthToken = tokenResult.authToken;
- [self performTokenOperation];
- } else {
- [self finishWithResult:FIRInstanceIDTokenOperationError token:nil error:error];
- }
- }];
- }
- - (void)finishWithResult:(FIRInstanceIDTokenOperationResult)result
- token:(nullable NSString *)token
- error:(nullable NSError *)error {
- // Add a check to prevent this finish from being called more than once.
- if (self.isFinished) {
- return;
- }
- self.dataTask = nil;
- _result = result;
- // TODO(chliangGoogle): Call these in the main thread?
- for (FIRInstanceIDTokenOperationCompletion completionHandler in self.completionHandlers) {
- completionHandler(result, token, error);
- }
- [self setExecuting:NO];
- [self setFinished:YES];
- }
- - (void)cancel {
- [super cancel];
- [self.dataTask cancel];
- [self finishWithResult:FIRInstanceIDTokenOperationCancelled token:nil error:nil];
- }
- - (void)performTokenOperation {
- }
- - (NSMutableURLRequest *)tokenRequest {
- NSString *authHeader =
- [FIRInstanceIDTokenOperation HTTPAuthHeaderFromCheckin:self.checkinPreferences];
- return [[self class] requestWithAuthHeader:authHeader FISAuthToken:self.FISAuthToken];
- }
- #pragma mark - Request Construction
- + (NSMutableURLRequest *)requestWithAuthHeader:(NSString *)authHeaderString
- FISAuthToken:(NSString *)FISAuthToken {
- NSURL *url = [NSURL URLWithString:FIRInstanceIDRegisterServer()];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- // Add HTTP headers
- [request setValue:authHeaderString forHTTPHeaderField:@"Authorization"];
- [request setValue:FIRInstanceIDAppIdentifier() forHTTPHeaderField:@"app"];
- if (FISAuthToken) {
- [request setValue:FISAuthToken forHTTPHeaderField:@"x-goog-firebase-installations-auth"];
- }
- request.HTTPMethod = @"POST";
- return request;
- }
- + (NSMutableArray<FIRInstanceIDURLQueryItem *> *)standardQueryItemsWithDeviceID:(NSString *)deviceID
- scope:(NSString *)scope {
- NSMutableArray<FIRInstanceIDURLQueryItem *> *queryItems = [NSMutableArray arrayWithCapacity:8];
- // E.g. X-osv=10.2.1
- NSString *systemVersion = FIRInstanceIDOperatingSystemVersion();
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"X-osv" value:systemVersion]];
- // E.g. device=
- if (deviceID) {
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"device" value:deviceID]];
- }
- // E.g. X-scope=fcm
- if (scope) {
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamScope
- value:scope]];
- }
- // E.g. plat=2
- NSString *platform = [NSString stringWithFormat:@"%ld", (long)kFIRInstanceIDPlatformVersionIOS];
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"plat" value:platform]];
- // E.g. app=com.myapp.foo
- NSString *appIdentifier = FIRInstanceIDAppIdentifier();
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"app" value:appIdentifier]];
- // E.g. app_ver=1.5
- NSString *appVersion = FIRInstanceIDCurrentAppVersion();
- [queryItems addObject:[FIRInstanceIDURLQueryItem queryItemWithName:@"app_ver" value:appVersion]];
- // E.g. X-cliv=fiid-1.2.3
- NSString *fcmLibraryVersion =
- [NSString stringWithFormat:@"fiid-%@", FIRInstanceIDCurrentGCMVersion()];
- if (fcmLibraryVersion.length) {
- FIRInstanceIDURLQueryItem *gcmLibVersion =
- [FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamFCMLibVersion
- value:fcmLibraryVersion];
- [queryItems addObject:gcmLibVersion];
- }
- return queryItems;
- }
- - (NSArray<FIRInstanceIDURLQueryItem *> *)queryItemsWithInstanceID:(NSString *)instanceID {
- return @[ [FIRInstanceIDURLQueryItem queryItemWithName:kFIRInstanceIDParamInstanceID
- value:instanceID] ];
- }
- #pragma mark - HTTP Header
- + (NSString *)HTTPAuthHeaderFromCheckin:(FIRInstanceIDCheckinPreferences *)checkin {
- NSString *deviceID = checkin.deviceID;
- NSString *secret = checkin.secretToken;
- return [NSString stringWithFormat:@"AidLogin %@:%@", deviceID, secret];
- }
- @end
|