| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // Copyright 2017 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 "FirebaseStorageInternal/Sources/FIRStorageTokenAuthorizer.h"
- #import "FirebaseStorageInternal/Sources/Public/FirebaseStorageInternal/FIRStorage.h"
- #import "FirebaseStorageInternal/Sources/Public/FirebaseStorageInternal/FIRStorageConstants.h"
- #import "FirebaseStorageInternal/Sources/FIRStorageConstants_Private.h"
- #import "FirebaseStorageInternal/Sources/FIRStorageErrors.h"
- #import "FirebaseStorageInternal/Sources/FIRStorageLogger.h"
- #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
- #import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h"
- #import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h"
- #import "FirebaseAuth/Interop/FIRAuthInterop.h"
- static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck";
- static NSString *const kAuthHeader = @"Authorization";
- @implementation FIRStorageTokenAuthorizer {
- @private
- /// Google App ID to pass along with each request.
- NSString *_googleAppID;
- /// Auth provider.
- id<FIRAuthInterop> _auth;
- id<FIRAppCheckInterop> _appCheck;
- }
- @synthesize fetcherService = _fetcherService;
- - (instancetype)initWithGoogleAppID:(NSString *)googleAppID
- fetcherService:(GTMSessionFetcherService *)service
- authProvider:(nullable id<FIRAuthInterop>)auth
- appCheck:(nullable id<FIRAppCheckInterop>)appCheck {
- self = [super init];
- if (self) {
- _googleAppID = googleAppID;
- _fetcherService = service;
- _auth = auth;
- _appCheck = appCheck;
- }
- return self;
- }
- #pragma mark - GTMFetcherAuthorizationProtocol methods
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-implementations"
- - (void)authorizeRequest:(NSMutableURLRequest *)request
- delegate:(id)delegate
- didFinishSelector:(SEL)sel {
- #pragma clang diagnostic push
- // Set version header on each request
- NSString *versionString = [NSString stringWithFormat:@"ios/%@", FIRFirebaseVersion()];
- [request setValue:versionString forHTTPHeaderField:@"x-firebase-storage-version"];
- // Set GMP ID on each request
- [request setValue:_googleAppID forHTTPHeaderField:@"x-firebase-gmpid"];
- if (delegate && sel) {
- id selfParam = self;
- NSMethodSignature *sig = [delegate methodSignatureForSelector:sel];
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
- [invocation setSelector:sel];
- [invocation setTarget:delegate];
- [invocation setArgument:&selfParam atIndex:2];
- [invocation setArgument:&request atIndex:3];
- dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue;
- if (!callbackQueue) {
- callbackQueue = dispatch_get_main_queue();
- }
- [invocation retainArguments];
- dispatch_group_t fetchTokenGroup = dispatch_group_create();
- if (_auth) {
- dispatch_group_enter(fetchTokenGroup);
- [_auth getTokenForcingRefresh:NO
- withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
- if (error) {
- NSMutableDictionary *errorDictionary =
- [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
- errorDictionary[kFIRStorageResponseErrorDomain] = error.domain;
- errorDictionary[kFIRStorageResponseErrorCode] = @(error.code);
- NSError *tokenError = [FIRStorageErrors
- errorWithCode:FIRIMPLStorageErrorCodeUnauthenticated
- infoDictionary:errorDictionary];
- [invocation setArgument:&tokenError atIndex:4];
- } else if (token) {
- NSString *firebaseToken =
- [NSString stringWithFormat:kFIRStorageAuthTokenFormat, token];
- [request setValue:firebaseToken forHTTPHeaderField:kAuthHeader];
- }
- dispatch_group_leave(fetchTokenGroup);
- }];
- }
- if (_appCheck) {
- dispatch_group_enter(fetchTokenGroup);
- [_appCheck getTokenForcingRefresh:NO
- completion:^(id<FIRAppCheckTokenResultInterop> tokenResult) {
- [request setValue:tokenResult.token
- forHTTPHeaderField:kAppCheckTokenHeader];
- if (tokenResult.error) {
- FIRLogDebug(kFIRLoggerStorage, kFIRStorageMessageCodeAppCheckError,
- @"Failed to fetch AppCheck token. Error: %@",
- tokenResult.error);
- }
- dispatch_group_leave(fetchTokenGroup);
- }];
- }
- dispatch_group_notify(fetchTokenGroup, callbackQueue, ^{
- [invocation invoke];
- });
- }
- }
- // Note that stopAuthorization, isAuthorizingRequest, and userEmail
- // aren't relevant with the Firebase App/Auth implementation of tokens,
- // and thus aren't implemented. Token refresh is handled transparently
- // for us, and we don't allow the auth request to be stopped.
- // Auth is also not required so the world doesn't stop.
- - (void)stopAuthorization {
- // Noop
- }
- - (void)stopAuthorizationForRequest:(NSURLRequest *)request {
- // Noop
- }
- - (BOOL)isAuthorizingRequest:(NSURLRequest *)request {
- return NO;
- }
- - (BOOL)isAuthorizedRequest:(NSURLRequest *)request {
- NSString *authHeader = request.allHTTPHeaderFields[@"Authorization"];
- BOOL isFirebaseToken = [authHeader hasPrefix:@"Firebase"];
- return isFirebaseToken;
- }
- - (NSString *)userEmail {
- // Noop
- return nil;
- }
- @end
|