Files
firebase-ios-sdk/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m
T

159 lines
5.1 KiB
Objective-C

/*
* 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 "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h"
#if __has_include(<FBLPromises/FBLPromises.h>)
#import <FBLPromises/FBLPromises.h>
#else
#import "FBLPromises.h"
#endif
#import <GoogleUtilities/GULKeychainUtils.h>
#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h"
static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens";
@interface FIRInstallationsIIDTokenInfo : NSObject <NSSecureCoding>
@property(nonatomic, nullable, copy) NSString *token;
@end
@implementation FIRInstallationsIIDTokenInfo
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
self = [super init];
if (self) {
_token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"];
}
return self;
}
@end
@interface FIRInstallationsIIDTokenStore ()
@property(nonatomic, readonly) NSString *GCMSenderID;
@end
@implementation FIRInstallationsIIDTokenStore
- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID {
self = [super init];
if (self) {
_GCMSenderID = GCMSenderID;
}
return self;
}
- (FBLPromise<NSString *> *)existingIIDDefaultToken {
return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
do:^id _Nullable {
return [self IIDDefaultTokenData];
}] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
then:^id _Nullable(NSData *_Nullable keychainData) {
return [self IIDCheckinWithData:keychainData];
}];
}
- (FBLPromise<NSString *> *)IIDCheckinWithData:(NSData *)data {
FBLPromise<NSString *> *resultPromise = [FBLPromise pendingPromise];
NSError *archiverError;
NSKeyedUnarchiver *unarchiver;
if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) {
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError];
} else {
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
#pragma clang diagnostic pop
} @catch (NSException *exception) {
archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception];
}
}
if (!unarchiver) {
NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
[resultPromise reject:error];
return resultPromise;
}
[unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"];
FIRInstallationsIIDTokenInfo *IIDTokenInfo =
[unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class]
forKey:NSKeyedArchiveRootObjectKey];
if (IIDTokenInfo.token.length < 1) {
[resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]];
return resultPromise;
}
[resultPromise fulfill:IIDTokenInfo.token];
return resultPromise;
}
- (FBLPromise<NSData *> *)IIDDefaultTokenData {
FBLPromise<NSData *> *resultPromise = [FBLPromise pendingPromise];
NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery];
NSError *error;
NSData *data = [GULKeychainUtils getItemWithQuery:keychainQuery error:&error];
if (data) {
[resultPromise fulfill:data];
return resultPromise;
} else {
NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData];
[resultPromise reject:outError];
return resultPromise;
}
}
- (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery {
NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword};
NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query];
finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId;
NSString *account = [self IIDAppIdentifier];
if ([account length]) {
finalQuery[(__bridge NSString *)kSecAttrAccount] = account;
}
finalQuery[(__bridge NSString *)kSecAttrService] =
[self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"];
return finalQuery;
}
- (NSString *)IIDAppIdentifier {
return [[NSBundle mainBundle] bundleIdentifier] ?: @"";
}
- (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope {
return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope];
}
@end