mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
124 lines
4.6 KiB
Objective-C
124 lines
4.6 KiB
Objective-C
/*
|
|||
|
|
* Copyright 2026 Google LLC
|
||
|
|
*
|
||
|
|
* 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 "FirebaseAppCheck/Sources/DebugProvider/FIRAppCheckDebugTokenConfigStore.h"
|
||
|
|
|
||
|
|
#import <TargetConditionals.h>
|
||
|
|
#import <errno.h>
|
||
|
|
|
||
|
|
#import "FirebaseAppCheck/Sources/Core/FIRAppCheckLogger.h"
|
||
|
|
|
||
|
|
#import "FirebaseCore/Extension/FirebaseCoreInternal.h"
|
||
|
|
|
||
|
|
NS_ASSUME_NONNULL_BEGIN
|
||
|
|
|
||
|
|
#if TARGET_OS_SIMULATOR
|
||
|
|
/// Environment variable set by the Simulator to the host user's home directory.
|
||
|
|
static NSString *const kSimulatorHostHomeEnvKey = @"SIMULATOR_HOST_HOME";
|
||
|
|
|
||
|
|
/// Top-level key of the config store file mapping Google App IDs to debug tokens.
|
||
|
|
static NSString *const kTokensKey = @"tokens";
|
||
|
|
#endif // TARGET_OS_SIMULATOR
|
||
|
|
|
||
|
|
@implementation FIRAppCheckDebugTokenConfigStore
|
||
|
|
|
||
|
|
+ (NSString *)relativePath {
|
||
|
|
return @".config/configstore/firebase-appcheck.json";
|
||
|
|
}
|
||
|
|
|
||
|
|
#if TARGET_OS_SIMULATOR
|
||
|
|
/// Returns whether `error`, from reading the config store file, means that the file does not exist.
|
||
|
|
///
|
||
|
|
/// Besides a missing file, this includes a path component that is a regular file rather than a
|
||
|
|
/// directory (e.g., `~/.config`), since the config store cannot exist at that path either.
|
||
|
|
+ (BOOL)isMissingConfigStoreError:(nullable NSError *)error {
|
||
|
|
if ([error.domain isEqualToString:NSCocoaErrorDomain] &&
|
||
|
|
error.code == NSFileReadNoSuchFileError) {
|
||
|
|
return YES;
|
||
|
|
}
|
||
|
|
NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey];
|
||
|
|
if (![underlyingError isKindOfClass:[NSError class]]) {
|
||
|
|
return NO;
|
||
|
|
}
|
||
|
|
return [underlyingError.domain isEqualToString:NSPOSIXErrorDomain] &&
|
||
|
|
underlyingError.code == ENOTDIR;
|
||
|
|
}
|
||
|
|
#endif // TARGET_OS_SIMULATOR
|
||
|
|
|
||
|
|
+ (nullable NSString *)debugTokenForGoogleAppID:(NSString *)googleAppID {
|
||
|
|
return [self debugTokenForGoogleAppID:googleAppID
|
||
|
|
environment:[NSProcessInfo processInfo].environment];
|
||
|
|
}
|
||
|
|
|
||
|
|
+ (nullable NSString *)debugTokenForGoogleAppID:(NSString *)googleAppID
|
||
|
|
environment:
|
||
|
|
(NSDictionary<NSString *, NSString *> *)environment {
|
||
|
|
#if TARGET_OS_SIMULATOR
|
||
|
|
NSString *hostHome = environment[kSimulatorHostHomeEnvKey];
|
||
|
|
if (hostHome.length == 0 || googleAppID.length == 0) {
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
NSURL *fileURL = [[NSURL fileURLWithPath:hostHome
|
||
|
|
isDirectory:YES] URLByAppendingPathComponent:self.relativePath
|
||
|
|
isDirectory:NO];
|
||
|
|
NSError *readError;
|
||
|
|
NSData *data = [NSData dataWithContentsOfURL:fileURL options:0 error:&readError];
|
||
|
|
if (!data) {
|
||
|
|
// A missing file (or a path where it cannot exist) means the Firebase CLI flow is not in use.
|
||
|
|
if (![self isMissingConfigStoreError:readError]) {
|
||
|
|
FIRLogWarning(kFIRLoggerAppCheck,
|
||
|
|
kFIRLoggerAppCheckMessageCodeDebugTokenConfigStoreUnreadable,
|
||
|
|
@"Failed to read App Check debug tokens from ~/%@: %@", self.relativePath,
|
||
|
|
readError.localizedDescription);
|
||
|
|
}
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
NSError *parseError;
|
||
|
|
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
|
||
|
|
if (![json isKindOfClass:[NSDictionary class]]) {
|
||
|
|
FIRLogWarning(kFIRLoggerAppCheck, kFIRLoggerAppCheckMessageCodeDebugTokenConfigStoreUnreadable,
|
||
|
|
@"Failed to parse App Check debug tokens from ~/%@: %@", self.relativePath,
|
||
|
|
parseError.localizedDescription ?: @"expected a JSON object");
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
NSDictionary *tokens = json[kTokensKey];
|
||
|
|
if (!tokens) {
|
||
|
|
// A config store without `tokens` (e.g., `{}` after the last token was removed) is valid.
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
if (![tokens isKindOfClass:[NSDictionary class]]) {
|
||
|
|
FIRLogWarning(kFIRLoggerAppCheck, kFIRLoggerAppCheckMessageCodeDebugTokenConfigStoreUnreadable,
|
||
|
|
@"Failed to parse App Check debug tokens from ~/%@: `%@` is not a JSON object",
|
||
|
|
self.relativePath, kTokensKey);
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
NSString *token = tokens[googleAppID];
|
||
|
|
if (![token isKindOfClass:[NSString class]] || token.length == 0) {
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
return token;
|
||
|
|
#else
|
||
|
|
return nil;
|
||
|
|
#endif // TARGET_OS_SIMULATOR
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|
||
|
|
|
||
|
|
NS_ASSUME_NONNULL_END
|