summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m')
-rw-r--r--StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m340
1 files changed, 340 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m b/StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m
new file mode 100644
index 00000000..0ebcfc88
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/FirebaseInstanceID/Firebase/InstanceID/FIRInstanceIDTokenManager.m
@@ -0,0 +1,340 @@
+/*
+ * 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 "FIRInstanceIDTokenManager.h"
+
+#import "FIRInstanceIDAuthKeyChain.h"
+#import "FIRInstanceIDAuthService.h"
+#import "FIRInstanceIDCheckinPreferences.h"
+#import "FIRInstanceIDConstants.h"
+#import "FIRInstanceIDDefines.h"
+#import "FIRInstanceIDLogger.h"
+#import "FIRInstanceIDStore.h"
+#import "FIRInstanceIDTokenDeleteOperation.h"
+#import "FIRInstanceIDTokenFetchOperation.h"
+#import "FIRInstanceIDTokenInfo.h"
+#import "FIRInstanceIDTokenOperation.h"
+#import "NSError+FIRInstanceID.h"
+
+@interface FIRInstanceIDTokenManager () <FIRInstanceIDStoreDelegate>
+
+@property(nonatomic, readwrite, strong) FIRInstanceIDStore *instanceIDStore;
+@property(nonatomic, readwrite, strong) FIRInstanceIDAuthService *authService;
+@property(nonatomic, readonly, strong) NSOperationQueue *tokenOperations;
+
+@property(nonatomic, readwrite, strong) FIRInstanceIDAPNSInfo *currentAPNSInfo;
+
+@end
+
+@implementation FIRInstanceIDTokenManager
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _instanceIDStore = [[FIRInstanceIDStore alloc] initWithDelegate:self];
+ _authService = [[FIRInstanceIDAuthService alloc] initWithStore:_instanceIDStore];
+ [self configureTokenOperations];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self stopAllTokenOperations];
+}
+
+- (void)configureTokenOperations {
+ _tokenOperations = [[NSOperationQueue alloc] init];
+ _tokenOperations.name = @"com.google.iid-token-operations";
+ // For now, restrict the operations to be serial, because in some cases (like if the
+ // authorized entity and scope are the same), order matters.
+ // If we have to deal with several different token requests simultaneously, it would be a good
+ // idea to add some better intelligence around this (performing unrelated token operations
+ // simultaneously, etc.).
+ _tokenOperations.maxConcurrentOperationCount = 1;
+ if ([_tokenOperations respondsToSelector:@selector(qualityOfService)]) {
+ _tokenOperations.qualityOfService = NSOperationQualityOfServiceUtility;
+ }
+}
+
+- (void)fetchNewTokenWithAuthorizedEntity:(NSString *)authorizedEntity
+ scope:(NSString *)scope
+ instanceID:(NSString *)instanceID
+ options:(NSDictionary *)options
+ handler:(FIRInstanceIDTokenHandler)handler {
+ FIRInstanceIDLoggerDebug(kFIRInstanceIDMessageCodeTokenManager000,
+ @"Fetch new token for authorizedEntity: %@, scope: %@", authorizedEntity,
+ scope);
+ FIRInstanceIDTokenFetchOperation *operation =
+ [self createFetchOperationWithAuthorizedEntity:authorizedEntity
+ scope:scope
+ options:options
+ instanceID:instanceID];
+ FIRInstanceID_WEAKIFY(self);
+ FIRInstanceIDTokenOperationCompletion completion =
+ ^(FIRInstanceIDTokenOperationResult result, NSString *_Nullable token,
+ NSError *_Nullable error) {
+ FIRInstanceID_STRONGIFY(self);
+ if (error) {
+ handler(nil, error);
+ return;
+ }
+ NSString *firebaseAppID = options[kFIRInstanceIDTokenOptionsFirebaseAppIDKey];
+ FIRInstanceIDTokenInfo *tokenInfo = [[FIRInstanceIDTokenInfo alloc]
+ initWithAuthorizedEntity:authorizedEntity
+ scope:scope
+ token:token
+ appVersion:FIRInstanceIDCurrentAppVersion()
+ firebaseAppID:firebaseAppID];
+ tokenInfo.APNSInfo = [[FIRInstanceIDAPNSInfo alloc] initWithTokenOptionsDictionary:options];
+
+ [self.instanceIDStore
+ saveTokenInfo:tokenInfo
+ handler:^(NSError *error) {
+ if (!error) {
+ // Do not send the token back in case the save was unsuccessful. Since with
+ // the new asychronous fetch mechanism this can lead to infinite loops, for
+ // example, we will return a valid token even though we weren't able to store
+ // it in our cache. The first token will lead to a onTokenRefresh callback
+ // wherein the user again calls `getToken` but since we weren't able to save
+ // it we won't hit the cache but hit the server again leading to an infinite
+ // loop.
+ FIRInstanceIDLoggerDebug(
+ kFIRInstanceIDMessageCodeTokenManager001,
+ @"Token fetch successful, token: %@, authorizedEntity: %@, scope:%@",
+ token, authorizedEntity, scope);
+
+ if (handler) {
+ handler(token, nil);
+ }
+ } else {
+ if (handler) {
+ handler(nil, error);
+ }
+ }
+ }];
+ };
+ // Add completion handler, and ensure it's called on the main queue
+ [operation addCompletionHandler:^(FIRInstanceIDTokenOperationResult result,
+ NSString *_Nullable token, NSError *_Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(result, token, error);
+ });
+ }];
+ [self.tokenOperations addOperation:operation];
+}
+
+- (FIRInstanceIDTokenInfo *)cachedTokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity
+ scope:(NSString *)scope {
+ return [self.instanceIDStore tokenInfoWithAuthorizedEntity:authorizedEntity scope:scope];
+}
+
+- (void)deleteTokenWithAuthorizedEntity:(NSString *)authorizedEntity
+ scope:(NSString *)scope
+ instanceID:(NSString *)instanceID
+ handler:(FIRInstanceIDDeleteTokenHandler)handler {
+ if ([self.instanceIDStore tokenInfoWithAuthorizedEntity:authorizedEntity scope:scope]) {
+ [self.instanceIDStore removeCachedTokenWithAuthorizedEntity:authorizedEntity scope:scope];
+ }
+ // Does not matter if we cannot find it in the cache. Still make an effort to unregister
+ // from the server.
+ FIRInstanceIDCheckinPreferences *checkinPreferences = self.authService.checkinPreferences;
+ FIRInstanceIDTokenDeleteOperation *operation =
+ [self createDeleteOperationWithAuthorizedEntity:authorizedEntity
+ scope:scope
+ checkinPreferences:checkinPreferences
+ instanceID:instanceID
+ action:FIRInstanceIDTokenActionDeleteToken];
+
+ if (handler) {
+ [operation addCompletionHandler:^(FIRInstanceIDTokenOperationResult result,
+ NSString *_Nullable token, NSError *_Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(error);
+ });
+ }];
+ }
+ [self.tokenOperations addOperation:operation];
+}
+
+- (void)deleteAllTokensWithInstanceID:(NSString *)instanceID
+ handler:(FIRInstanceIDDeleteHandler)handler {
+ // delete all tokens
+ FIRInstanceIDCheckinPreferences *checkinPreferences = self.authService.checkinPreferences;
+ if (!checkinPreferences) {
+ // The checkin is already deleted. No need to trigger the token delete operation as client no
+ // longer has the checkin information for server to delete.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(nil);
+ });
+ return;
+ }
+ FIRInstanceIDTokenDeleteOperation *operation =
+ [self createDeleteOperationWithAuthorizedEntity:kFIRInstanceIDKeychainWildcardIdentifier
+ scope:kFIRInstanceIDKeychainWildcardIdentifier
+ checkinPreferences:checkinPreferences
+ instanceID:instanceID
+ action:FIRInstanceIDTokenActionDeleteTokenAndIID];
+ if (handler) {
+ [operation addCompletionHandler:^(FIRInstanceIDTokenOperationResult result,
+ NSString *_Nullable token, NSError *_Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ handler(error);
+ });
+ }];
+ }
+ [self.tokenOperations addOperation:operation];
+}
+
+- (void)deleteAllTokensLocallyWithHandler:(void (^)(NSError *error))handler {
+ [self.instanceIDStore removeAllCachedTokensWithHandler:handler];
+}
+
+- (void)stopAllTokenOperations {
+ [self.authService stopCheckinRequest];
+ [self.tokenOperations cancelAllOperations];
+}
+
+#pragma mark - FIRInstanceIDStoreDelegate
+
+- (void)store:(FIRInstanceIDStore *)store
+ didDeleteFCMScopedTokensForCheckin:(FIRInstanceIDCheckinPreferences *)checkin {
+ // Make a best effort try to delete the old client related state on the FCM server. This is
+ // required to delete old pubusb registrations which weren't cleared when the app was deleted.
+ //
+ // This is only a one time effort. If this call fails the client would still receive duplicate
+ // pubsub notifications if he is again subscribed to the same topic.
+ //
+ // The client state should be cleared on the server for the provided checkin preferences.
+ FIRInstanceIDTokenDeleteOperation *operation =
+ [self createDeleteOperationWithAuthorizedEntity:nil
+ scope:nil
+ checkinPreferences:checkin
+ instanceID:nil
+ action:FIRInstanceIDTokenActionDeleteToken];
+ [operation addCompletionHandler:^(FIRInstanceIDTokenOperationResult result,
+ NSString *_Nullable token, NSError *_Nullable error) {
+ if (error) {
+ FIRInstanceIDMessageCode code =
+ kFIRInstanceIDMessageCodeTokenManagerErrorDeletingFCMTokensOnAppReset;
+ FIRInstanceIDLoggerDebug(code, @"Failed to delete GCM server registrations on app reset.");
+ } else {
+ FIRInstanceIDLoggerDebug(kFIRInstanceIDMessageCodeTokenManagerDeletedFCMTokensOnAppReset,
+ @"Successfully deleted GCM server registrations on app reset");
+ }
+ }];
+
+ [self.tokenOperations addOperation:operation];
+}
+
+#pragma mark - Unit Testing Stub Helpers
+// We really have this method so that we can more easily stub it out for unit testing
+- (FIRInstanceIDTokenFetchOperation *)
+ createFetchOperationWithAuthorizedEntity:(NSString *)authorizedEntity
+ scope:(NSString *)scope
+ options:(NSDictionary<NSString *, NSString *> *)options
+ instanceID:(NSString *)instanceID {
+ FIRInstanceIDCheckinPreferences *checkinPreferences = self.authService.checkinPreferences;
+ FIRInstanceIDTokenFetchOperation *operation =
+ [[FIRInstanceIDTokenFetchOperation alloc] initWithAuthorizedEntity:authorizedEntity
+ scope:scope
+ options:options
+ checkinPreferences:checkinPreferences
+ instanceID:instanceID];
+ return operation;
+}
+
+// We really have this method so that we can more easily stub it out for unit testing
+- (FIRInstanceIDTokenDeleteOperation *)
+ createDeleteOperationWithAuthorizedEntity:(NSString *)authorizedEntity
+ scope:(NSString *)scope
+ checkinPreferences:(FIRInstanceIDCheckinPreferences *)checkinPreferences
+ instanceID:(NSString *)instanceID
+ action:(FIRInstanceIDTokenAction)action {
+ FIRInstanceIDTokenDeleteOperation *operation =
+ [[FIRInstanceIDTokenDeleteOperation alloc] initWithAuthorizedEntity:authorizedEntity
+ scope:scope
+ checkinPreferences:checkinPreferences
+ instanceID:instanceID
+ action:action];
+ return operation;
+}
+
+#pragma mark - Invalidating Cached Tokens
+- (BOOL)checkTokenRefreshPolicyWithIID:(NSString *)IID {
+ // We know at least one cached token exists.
+ BOOL shouldFetchDefaultToken = NO;
+ NSArray<FIRInstanceIDTokenInfo *> *tokenInfos = [self.instanceIDStore cachedTokenInfos];
+
+ NSMutableArray<FIRInstanceIDTokenInfo *> *tokenInfosToDelete =
+ [NSMutableArray arrayWithCapacity:tokenInfos.count];
+ for (FIRInstanceIDTokenInfo *tokenInfo in tokenInfos) {
+ if ([tokenInfo isFreshWithIID:IID]) {
+ // Token is fresh and in right format, do nothing
+ continue;
+ }
+ if ([tokenInfo isDefaultToken]) {
+ // Default token is expired, do not mark for deletion. Fetch directly from server to
+ // replace the current one.
+ shouldFetchDefaultToken = YES;
+ } else {
+ // Non-default token is expired, mark for deletion.
+ [tokenInfosToDelete addObject:tokenInfo];
+ }
+ FIRInstanceIDLoggerDebug(
+ kFIRInstanceIDMessageCodeTokenManagerInvalidateStaleToken,
+ @"Invalidating cached token for %@ (%@) due to token is no longer fresh.",
+ tokenInfo.authorizedEntity, tokenInfo.scope);
+ }
+ for (FIRInstanceIDTokenInfo *tokenInfoToDelete in tokenInfosToDelete) {
+ [self.instanceIDStore removeCachedTokenWithAuthorizedEntity:tokenInfoToDelete.authorizedEntity
+ scope:tokenInfoToDelete.scope];
+ }
+ return shouldFetchDefaultToken;
+}
+
+- (NSArray<FIRInstanceIDTokenInfo *> *)updateTokensToAPNSDeviceToken:(NSData *)deviceToken
+ isSandbox:(BOOL)isSandbox {
+ // Each cached IID token that is missing an APNSInfo, or has an APNSInfo associated should be
+ // checked and invalidated if needed.
+ FIRInstanceIDAPNSInfo *APNSInfo = [[FIRInstanceIDAPNSInfo alloc] initWithDeviceToken:deviceToken
+ isSandbox:isSandbox];
+ if ([self.currentAPNSInfo isEqualToAPNSInfo:APNSInfo]) {
+ return @[];
+ }
+ self.currentAPNSInfo = APNSInfo;
+
+ NSArray<FIRInstanceIDTokenInfo *> *tokenInfos = [self.instanceIDStore cachedTokenInfos];
+ NSMutableArray<FIRInstanceIDTokenInfo *> *tokenInfosToDelete =
+ [NSMutableArray arrayWithCapacity:tokenInfos.count];
+ for (FIRInstanceIDTokenInfo *cachedTokenInfo in tokenInfos) {
+ // Check if the cached APNSInfo is nil, or if it is an old APNSInfo.
+ if (!cachedTokenInfo.APNSInfo ||
+ ![cachedTokenInfo.APNSInfo isEqualToAPNSInfo:self.currentAPNSInfo]) {
+ // Mark for invalidation.
+ [tokenInfosToDelete addObject:cachedTokenInfo];
+ }
+ }
+ for (FIRInstanceIDTokenInfo *tokenInfoToDelete in tokenInfosToDelete) {
+ FIRInstanceIDLoggerDebug(kFIRInstanceIDMessageCodeTokenManagerAPNSChangedTokenInvalidated,
+ @"Invalidating cached token for %@ (%@) due to APNs token change.",
+ tokenInfoToDelete.authorizedEntity, tokenInfoToDelete.scope);
+ [self.instanceIDStore removeCachedTokenWithAuthorizedEntity:tokenInfoToDelete.authorizedEntity
+ scope:tokenInfoToDelete.scope];
+ }
+ return tokenInfosToDelete;
+}
+
+@end